Conversation

mbuliard
QA
Bug fix?no
New feature?yes
Docs?yes
IssuesNo
LicenseMIT

The purpose of this MR is to give the responsability of changing the URL to the backend, allowing to use Symfony Router and to have LiveProps in the path, not only in query parameters :
http://example.com/content?id=123 vs
http://example.com/content/123

To set the LiveProp in the path, a new option, mapPath has been added to the UrlMapping option of the LiveProp :

#[LiveProp(writable: true, url: new UrlMapping(mapPath: true))]
public int $id;

WORKFLOW

  1. When sending a request to the backend, the frontend add a new header X-Live-Url containing the current path and query parameters.
  2. On KernelResponse event, the new path and query string is calculated from the header received and the new props and put in the response header X-Live-Url.
  3. When the frontend receives the response, the current path and query are placed by those received, via history.replaceState.

BACKEND CHANGES

  • New UrlFactory service to generate URL from the previous one, the path-mapped props and the query-mapped props. The url is first generated by the Symfony Router, using the previous one and the path-mapped props. Then the query-mapped props and the previous query parameters are added.
  • QueryStringPropsExtractor is renamed to RequestPropsExtractor and now extract props from the request attributes and query parameters.
  • UrlMapping now has a new option mapPath, boolean, false by default.
  • LiveComponentMetadata has new method getAllUrlMappings returning urlMappings of all LiveProps.
  • QueryStringInitializeSubscriber is renamed to RequestInitializeSubscriber
  • new LiveUrlSubscriber, listening to KernelResponse, and setting the X-Live-Url of the response with the new URL, generated by the UrlFactory. To generate it, the previous location is extracted from the request and the props are extracted from metadata, hydrated with the values of _live_request_data and sorted between path-mapped and query-mapped.
  • LiveComponentSubscriber now add responseProps data to the _live_request_data attribute, containing the mounted component data when the action is not the default one. This change is made to take server-side changes into account.
  • LiveComponentMetadata has new method getAllUrlMappings returning urlMappings of all LiveProps.

FRONTEND CHANGES

  • Backend/RequestBuilder now add the current pathname and search as X-Live-Url header in the request.
  • Backend/BackendResponse has new property liveUrl, populated from the HTTP response X-Live-Url header.
  • Component/index.ts : performRequest now check for X-Live-Url header in response and, when found, do history.replace with the new url and the current hash and origin.
  • url_utils is removed.
  • Component/plugins/QueryStringPlugin is removed.

TODO

Review :-)

@carsonbotcarsonbot added FeatureNew FeatureStatus: Needs WorkAdditional work is neededlabels Apr 1, 2025
@github-actionsGitHub Actions

📊 Packages dist files size difference

Thanks for the PR! Here is the difference in size of the packages dist files between the base branch and the PR.
Please review the changes and make sure they are expected.

FileBefore (Size / Gzip)After (Size / Gzip)
LiveComponent
Backend/BackendResponse.d.ts136 B / 139 B199 B+46% 📈 / 163 B+17% 📈
Component/plugins/QueryStringPlugin.d.ts356 B / 239 BRemoved
live_controller.d.ts3.3 kB / 924 B3.1 kB-6% 📉 / 893 B-3% 📉
live_controller.js120.02 kB / 23.4 kB116.68 kB-3% 📉 / 22.57 kB-4% 📉
url_utils.d.ts306 B / 205 BRemoved

@mbuliardmbuliard marked this pull request as draft April 1, 2025 19:23
@smnandre

(Had a quick chat with @mbuliard yesterday — he's making a few adjustments before opening the PR. Stay tuned! 😄 )

@mbuliardmbuliard force-pushed the live-url branch 6 times, most recently from 93c0a12 to d848b54 Compare April 10, 2025 11:34
@smnandre

Do you want/need any help here @mbuliard ?

@mbuliardmbuliard force-pushed the live-url branch 7 times, most recently from ceabe03 to 04dc91a Compare May 12, 2025 16:34
@mbuliard

Do you want/need any help here @mbuliard ?

Thanks ! I needed free time, but the PR is almost done. Related tests are green, but I shall now add my own testing of the backend.

What took me some time was to the handling of custom actions, who may (and often do) update component props. I choose to store the updated component props in _live_request_data.responseProps, next to props and updated values.
I'm thinking to always populate these responseProps, even for default action and then simplifying my LiveUrlSubscriber.

@mbuliardmbuliard force-pushed the live-url branch 8 times, most recently from 9393039 to df97b2f Compare May 22, 2025 15:46
@carsonbotcarsonbot added Status: Needs ReviewNeeds to be reviewedand removed Status: Needs WorkAdditional work is neededlabels May 30, 2025
@mbuliardmbuliard force-pushed the live-url branch 3 times, most recently from aeaea56 to c31983f Compare June 9, 2025 08:52
@smnandre

To me it's 💯 👍 ..

@Kocal @kbond I'd like a second look on this!

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! Couple questions in my review but also: Can/should you have multiple routes per component? Or should multiple LiveProp's with mapPath: true all be contained in a single route?

I think this should be clarified but also: it looks to me like this fully overrides the route for your component? If so, what about this concept being the feature?

@mbuliard

@kbond
Thanks for your review !
Defining the Route in the Component would be an interesting idea but it would be far too big for this MR in my opinion.
For now, the mapPath option will only tell the LiveUrlSubscriber to try to set the LiveProp in the path instead of the query.

Can/should you have multiple routes per component? Or should multiple LiveProp's with mapPath: true all be contained in a single route?

The Route and the LiveProp are not programmatically linked to each other so there is no restriction : several LiveProps can be used for the same Route and each LiveProp can be used for several Routes.

@kbond

@mbuliard, sorry, I misunderstood the feature. It took me a bit to realize the docs showed the route/controller that renders the component initially.

@mbuliardmbuliard force-pushed the live-url branch 2 times, most recently from b4baef5 to da77265 Compare June 11, 2025 16:01
@mbuliardmbuliard force-pushed the live-url branch 2 times, most recently from 2e3be93 to 9df1066 Compare June 11, 2025 16:13
@mbuliard

@mbuliard, sorry, I misunderstood the feature. It took me a bit to realize the docs showed the route/controller that renders the component initially.

My example was not clear enough, I added a line to clarify that it was a controller.

Sign up for free to join this conversation on . Already have an account? Sign in to comment
FeatureNew FeatureStatus: Needs ReviewNeeds to be reviewed
None yet

Successfully merging this pull request may close these issues.