Problem/Motivation
Over in #306662: Add redirect option to site-wide contact forms we want to allow admins to choose the redirect path after form submission.
But we want to store a route (as per route schema type) and not a path.
But we don't want users to enter a route name and parameters cause ick.
Also Tour UI (Contrib) will need to select routes.
Other places could possibly use this too.
Lets add a #type => 'path'.
Let's make it optionally validate paths and optionally convert paths to Drupal\Core\Url object or a route name and route parameters array.
Proposed resolution
New #type 'path'
New #validate_path option on #type => path to validate path as valid route.
New #convert_path option on #type => path to convert to either Drupal\Core\Url object or route name and route parameters pair on form submission.
Remaining tasks
Reviews
User interface changes
None
API changes
New #type 'path'.
Comment | File | Size | Author |
---|---|---|---|
#63 | path-element-2321745.63.patch | 9.94 KB | larowlan |
#63 | interdiff.txt | 295 bytes | larowlan |
#59 | path-element-2321745.59.patch | 9.92 KB | larowlan |
#59 | interdiff.txt | 295 bytes | larowlan |
#53 | path-element-2321745.53.patch | 9.94 KB | larowlan |
Comments
Comment #1
larowlanScreenshot
patch coming once tests pass
Comment #2
larowlanHere tis'
Comment #3
tim.plunkettThis is really cool!
This could do parent::getInfo() and just add the #element_validate
Wow, this is a heavy method, glad its on save, not runtime.
I think this method needs some inline docs.
I'd like to avoid adding more to FormTest. I like what we did in FormDefaultHandlersTest, where the test class implements FormInterface, and everything is self-contained
Comment #4
larowlanFixes 3.1 and 3.2
3.3 will need to come later, if someone else wants to beat me to it - go ahead.
Comment #5
tim-e CreditAttribution: tim-e commentedCan we get the base_url from the current Request object instead of directly from $GLOBALS?
Comment #7
larowlan@tim-e yep, you're correct - and thats why it failed too.
fixes #5
Comment #10
larowlannot working in a subfolder...
Comment #11
dawehnerYou should rather do something like this: \Drupal\Core\Url::createFromPath($element['#value']), with a try catch around it. then you can pull the route name + parameters from there.
Comment #12
larowlanthanks @dawehner, 1230454% better.
/me adds another thing to list of things dawehner has taught him
Comment #13
dawehnerCan we document the new methods as well?
Did you considered to return an url object directly? We use it in a hell lot of places already. The concept would be kinda similar to an entity form which sets the entity itself onto the form state. Oppinions?
I wonder whether we could just use the StringTranslationTrait and use $this->t()
let's mark it as public
Wow, this is a crazy trick!
Comment #15
larowlanIt's a static method so we have no DI or string translation trait :(
Comment #18
dawehnerWell, what about adding a follow up to provide a static version of the trait, so static::t() and static::formatPlural() would be supported? This could be for example also used for baseFieldDefinitions?
Comment #19
sunAdding two closely related issues.
Somehow I was under the impression that this form element #type would have existed in the past (~D5), but wasn't able to find it. In any case, +1.
This #type somewhat belongs to Link module + Menu* modules, as well as Path module. Due to that, it's probably good to define it globally in System module.
However, that also means that there are various possible incarnations of a "path" UI element/widget. We should investigate whether more specialized element use-cases can be derived from the base/generic element type, and ensure that the architecture and DX makes sense.
In addition, the HTML5 standard input form element #type
'url'
co-exists next to this. Add path, link, menu_link, etc to that, and things get confusing very fast.I'd start by renaming this new #type from
'matched_path'
to just'path'
: A form input element that accepts an internal system path.Additionally matching an existing path against available routes is an act of user input (#element_validate) validation, which e.g. could be controlled by a
#validate_route => TRUE/FALSE
property on the element.Additionally replacing a user-entered 'path' with the name of the matched route is an act of user input/form state #value post-processing, which e.g. could be controlled by
#submit_route => TRUE/FALSE
property on the element.Comment #20
larowlanMakes sense
Comment #22
larowlanChanges to
'#type' => 'path'
Renames to PathElement
Moves test to KernelTestBase as per 3.3
Doesn't do static StringTranslationTrait.
Adds
'#validate_path' => TRUE|FALSE
Adds
'#convert_path' => PathElement::CONVERT_NONE|PathElement::CONVERT_ROUTE|PathElement::CONVERT_URL
Convert none => leaves as is
Convert route => converts to array with route_name and route_parameters
Convert URL => converts to URL value object as per 13.2
Note that #convert_path other than None implies #validate as you need to validate to convert.
Comment #23
larowlanComment #24
tim.plunkettSo now these two brand new properties are specific to a single validator, and have no default values.
That seems like a mistake.
Also, this static method and constants are on
PathElement extends Textfield
, meaning everyone needs to extend Textfield to get that. Could traits help us here?Comment #25
sun@tim.plunkett: Could you clarify your concerns? Where and how do you see a need/use-case for horizontal extensibility?
More specialized implementations are covered by subclassing already. And in case that isn't sufficient for any reason, then at least the #element_validate callback can be re-used by simply specifying it in your own code (but I can't see a use-case for that).
Comment #26
tim.plunkettI misread/misunderstood the change, sorry.
Though I would like to see one element/test case added when not specifying #convert_path to prove it is truly optional.
Comment #27
larowlanAdded case as per #26
Comment #28
tim.plunkettSorry, should have called this out before. Please remove :)
I think this is good now.
Comment #29
larowlanoh, yep - thanks
Comment #30
tim.plunkettLooks good to me! Thanks.
Comment #34
larowlanrandom bot snafoos
Comment #35
tim-e CreditAttribution: tim-e commentedA couple of things when using this. I have created a form with a #type => 'path' element and ran into a couple of issues:
Comment #36
larowlanGreat finds @tim-e
Here's two patches, one with new tests to verify the issues you reported, another with fixes.
One should fail, the other pass
Comment #37
tim-e CreditAttribution: tim-e commentedTested and fixed, thanks larowlan
Comment #39
alexpottt() looks so old-skool :)
Should we not assert what this errors actually are?
Comment #40
tim.plunkettThe t() is unavoidable right now, since this method is static.
Addressed #39.2
Comment #41
webchickOverall this sounds very useful. But a couple of concerns:
1) We already have a #type => url for an HTML5 form input of a URL. Now we're also adding a #type => path. What's the difference? And can we just make #type => url a bit smarter so we can ditch path and don't need to explain the difference between two nearly identically-sounding form inputs? (Esp. given that "url" is a native HTML5 type and "path" is something we made up :))
2) If we do need both, it would help if there were any usages of this in core at all, so if I get confused I can at least use grep and figure out when core uses one or the other. But atm the only place this is used is in tests so that doesn't really help.
So the docs should make it clear when to use one or the other, if we have to keep both. Also:
This is gobbledygook to me. :)
Comment #42
larowlanThe use-case is #306662: Add redirect option to site-wide contact forms but neither @tim.plunkett or I were aware of #type => url, so I think it does make sense to extend it to provide route validation and conversion functions.
I will tackle it from that front.
Comment #43
larowlanUpdated issue summary and title to reflect new approach after discovering we have a #type url already.
Comment #44
sunNote that
#type 'url'
produces a HTML5input[type=url]
element, which is validated to be a fully-qualified URL by UAs.cf. #2054011: Implement built-in support for internal URLs (Link module/field)
Comment #45
larowlanThanks, will see if browser validation trips us up here, in which case we might need to revert back to #type => path?
Comment #46
larowlanRe-roll
We can't use #type url so we're back to #type path.
Back to original plan.
Comment #48
larowlanComment #49
larowlanComment #51
larowlanAlready a URL in that namespace
Comment #52
larowlanMissed interdiff at 40, this is ready for review again, but is essentially same patch as 40 - so rtbc?
Comment #53
larowlanRe-roll after #2323721: [sechole] Link field item and menu link information leakage which made Url::createFromPath non-recommended approach
Comment #54
tim-e CreditAttribution: tim-e commentedComment #58
andypostComment #59
larowlanTrivial re-roll
Comment #60
tim.plunkettHmmm, shouldn't this have been core/modules/system/tests/src/Unit/ ?
Comment #61
larowlanEven for kernel tests?
Comment #62
tim.plunkettKernel tests still extend web tests, wouldn't they still be in core/modules/system/src/Tests?
Nothing should be in core/modules/system/src/Element.
Comment #63
larowlanComment #64
larowlanThanks @tim.plunkett
Comment #65
tim.plunkettThanks! RTBC +1
Comment #66
alexpottCommitted ce8dcd4 and pushed to 8.0.x. Thanks!
Comment #69
Anonymous (not verified) CreditAttribution: Anonymous commentedFollow-up #2832856: Improve PathElementFormTest