-
-
Notifications
You must be signed in to change notification settings - Fork 356
[LiveComponent] Alias URL bound props #1396
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Is it accessible in PHP easily ? |
It's in the |
*/ | ||
private bool $url = false, | ||
private bool|QueryMapping $url = false, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of having the mapping in the url argument, is it not more readable to have a separate argument alias?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I like it inside of url
as a QueryMapping
. There will be other options coming in the future too. But we could talk about the naming: maybe UrlMapping
to match the url
config?
Thanks for this! What's the use-case for needing to do:
This doesn't look like something that Livewire has (I check there as a quick way to validate the value of features). Also: |
But... it's on a call per call basis... so a call to metadataFactory would not bring this data right ? So it's not usable in events, cache, etc ? (just want to clarify when/where this data will be exposed, accessible, etc) |
I'm not sure to understand how the live prop mapping is "kept" during live action / event.. but it's probably just me needing coffee.. |
If the users just want to override this mapping property they can do it with this shortened syntax instead of passing an object. It may also be useful in the future when the mapping object contain other options: it will be easier to conditionally render specific attributes in this way, than setting up an object, IMO.
That's true, but I tried the Livewire feature, and honestly I missed it. As far I know, you can't avoid parameter name collision in Livewire, but I find it pretty useful.
I'm totally open for any renaming :)
The metadata defined in your PHP component is available through the metadata factory. If you override the mapping in a template, the overridden values will not be available from metadata. Though there is a utility class that helps in getting those values from mounted attributes.
The mapping is render as a Stimulus value here. |
I'm still not sure if i'm paranoiac ... but if you're telling me that the "mapping configuration" is read and used from request data ... I'm 90% sure i still miss something so i stop here :) |
5a0976a
to
2ba3c69
Compare
I renamed QueryMapping to UrlMapping, alias to as, and rebased to add some doc on this feature :) |
src/LiveComponent/doc/index.rst
Outdated
<twig:SearchModule :data-live-url-mapping-query="{ alias: 'q'}" /> | ||
|
||
{# Or configure the mapping option directly #} | ||
<twig:SearchModule data-live-url-mapping-query-alias="q" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's talk about this approach :). What I don't love about it is that users need to know about more data
attribute options. And we need to make sure we keep this value on the frontend so we can reference it on re-renders.
The Livewire solution is to allow the mapping to be done in a method if you have something custom: https://livewire.laravel.com/docs/url#using-the-querystring-method
We could even go more generic: adding some way of configure a LiveProp
entirely:
#[AsLiveComponent]
class SearchModule
{
#[LiveProp(writable: true, 'modifier' => 'modifyQueryProp')]
public string $query = '';
#[LiveProp]
public string $alias = null;
public function modifyQueryProp(LiveProp $prop): void
{
if (!$this->alias) {
return;
}
$prop->url = new UrlMapping(as: $this->alias);
}
}
Usage:
<twig:SearchModule alias="q" />
A tiny bit more work for the user, but I think it's more understandable (and will also be more flexible). WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh I like it! It looks even easier to set up. I have a few questions in mind:
- Does the
alias
prop need to be aLiveProp
? - We need to make
LiveProp
writable in some way, is there any drawback? - The
modifier
method will need the component to be mounted before it's called, so we can use data passed from templates. Are we sure allLiveProp
options are safe to be overridden here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome!
Does the
alias
prop need to be aLiveProp
?
I think so, yes - because we need some way to persist this setting across re-renders. You were doing that before by making sure to always render the attribute. This, at least, uses a known mechanism.
We need to make
LiveProp
writable in some way, is there any drawback?
There could be, yes - you're correct to worry about this. Currently, you can grab a LiveProp[]
from a component in a static way: that metadata is always the same for a given component class. I've just started looking at the component. The LiveComponentMetadata
(which holds the LiveProp
info) is nicely created only by the LiveComponentMetadataFactory
. This would be the ideal situation: if we could continue to rely on LiveComponentMetadataFactory::getMetadata()
everywhere and it would handle this new modifier
config).
However, the signature currently is:
public function getMetadata(string $name): LiveComponentMetadata
It would need to become:
public function getMetadata(string $name, object $component): LiveComponentMetadata
Looking at the code that calls this, that's a problem in at least one spot: ChildComponentPartialRenderer
. When a parent component re-renders, this component is responsible for figuring out whether or not the child components need to re-render (based on if the input props changed to the child). To do this, it needs the LiveComponentMetadata
so it can read an updateFromParent
option on each LiveProp
. If we do not need to re-render the child, then we even avoid creating it. See the problem? With my idea, we would need to mount/create the child component in order to see if it needs to be re-rendered.
But, this is the ONLY place where that's a problem. A git grep '\->getMetadata(\$' src/LiveComponent
shows a few other places where we call this method, but all of the have access to the $component
object. In other words adding a 2nd argument would not be a problem. The LiveProp
would need to become mutable... though if we want, we could actually keep it immutable and use ->with()
methods to modify it - e.g.
- $prop->url = new UrlMapping(as: $this->alias);
- return $prop->withUrlMapping(new UrlMapping(as: $this->alias));
Where ->withUrlMapping()
creates a new instance of itself. A bit more work for the user, but this is not a main use-case.
If we like this, we could work around the ChildComponentPartialRenderer
, I think. This could be ONE spot where do something different to find these LiveProp
with updateFromParent
(and this property would NOT have a with()
method to change it dynamically). We could, for example, add an internal LiveComponentMetadataFactory::getMetadataWithoutModifiers(string $name)
that would do what it does now: return the metadata but without calling the modifier
). It would be internal and only used in the one special case of ChildComponentPartialRenderer
.
The modifier method will need the component to be mounted before it's called, so we can use data passed from templates. Are we sure all LiveProp options are safe to be overridden here?
Based on the above research and because all metadata is created from LiveComponentMetadataFactory
, I think yes, they are all safe to be changed except for updateFromParent
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the investigations! So now this "side feature" of the alias option is growing up. I would remove it from this PR and work on it in a dedicated one, where we could specifically address the ChildComponentPartialRenderer
modifications you mentioned above. Wdyt?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ha! Indeed it is - it's exposed a bigger thing!
I would remove it from this PR and work on it in a dedicated one, where we could specifically address the ChildComponentPartialRenderer modifications you mentioned above. Wdyt?
It'd be great to focus on that part in a smaller PR. But as LiveComponents will become stable at the end of Feb, I don't want to merge this now, if it'll change later.
If you'd like, there could be a compromise: perhaps you create a PR now with this refactoring of the getMetadata()
method and ChildComponentPartialRenderer
? Then we get that merged and then update and merge this PR.
Thanks for your patient work - you PR's have proved to be complex in a good way: handling important things in the correct way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright, let's do this!
Thanks for your patient work - you PR's have proved to be complex in a good way: handling important things in the correct way.
Thank you!
This PR was squashed before being merged into the 2.x branch. Discussion ---------- [LiveComponent] Add modifier option to LiveProp | Q | A | ------------- | --- | Bug fix? | no | New feature? | yes | Issues | N/A | License | MIT Hi! Following discussions in [#1396](#1396 (comment)), here is a proposal to allow a `LiveProp` to be modified at runtime. The feature adds a `modifier` option to `LiveProp`, so users can use a custom method to modify the `LiveProp`'s options depending on the context. This context could be a service, or even another prop within the component. ### Usage Here is the example given in the doc: ```php #[AsLiveComponent] class ProductSearch { #[LiveProp(writable: true, modifier: 'modifyAddedDate')] public ?\DateTimeImmutable $addedDate; #[LiveProp] public string $dateFormat = 'Y-m-d'; // ... public function modifyAddedDate(LiveProp $prop): LiveProp { return $prop->withFormat($this->dateFormat); } } ``` ```twig {{ component('ProductSearch', { dateFormat: 'd/m/Y' }) }} ``` ### Changes overview First, we have to make the `LiveProp` attribute editable in some way. I opted out for immutable methods, so caching is preserved when applicable. Then add a `LivePropMetadata::withModifier(object $component)` method that returns a new instance modified by the user-defined method. This is called in a few places, similarly to `LiveComponentMetadata::calculateFieldName()`. The tricky part is component hydration. If we use props in modifiers to change other `LiveProp` options, they have to be hydrated before the modifier is applied. This is only useful for options related to hydration, but it concerns most of them... The trick is to sort metadata, so modified ones are hydrated at the end. Commits ------- 3bcc5c2 [LiveComponent] Add modifier option to LiveProp
9063962
to
21af89f
Compare
Hi there! Just rebased to get the LiveProp modifier feature. I also rewrote the test component for url bindings. We often add use cases and I found it becomes hard to understand things like "prop1", "prop2", etc in assertions. This is in a separate commit, so if it's not the best place do do this it can be removed easily ;) Doc section is also updated! |
21af89f
to
c284a63
Compare
@squrious where are we here ? Do you need something / is it "ready" for you ? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is great @squrious! One small nitpick.
ea57558
to
828e34e
Compare
Thanks Nicolas for your time and patience on this! |
Following #1230.
Allow custom parameter names for URL bound props, and mapping specification from Twig templates.
Usage
From PHP definition:
From templates:
HTML syntax also works:
Result
Changing the value of
search
will update the url tohttps://my.domain?q=my+search+string
.Mappings provided in Twig templates are merged into those provided in PHP. Thus, query mappings in PHP act as defaults, and we can override them in templates (e.g. for specific page requirements). So a page with:
will update its URL to
http://my.domain?search=foo&q=bar
.