I would like to display error message in the field it is for. I know how to put the error message into the field, but I want to find a dynamic way to check after re-submittion, if the inserted value is not the error message itself. I use doctrine annotations.
For example if the field is "title", the error message would be "The title must be filled!".
So the title field is not empty anymore, I click submit again, and it is valid now. I don't want to check every single field like
if $entity->getTitle() == "The title must be filled" ...
I've managed to do this with not displayed error divs in the twig, and jquery, but I want to know if there is a better way to do this from the controller? Thanks
You're asking how to correctly do something the wrong way... If the input value is not the value you want processed, it should have never been the value to begin with. That being said, I'm sure you have your reasons...
You need to listen to FormEvents::BIND_CLIENT_DATA and clear the form data if it matches your error string.
public function buildForm(FormBuilder $builder, array $options)
{
$builder->add('title');
$builder->get('title')->addEventListener(
FormEvents::BIND_CLIENT_DATA,
function(FilterDataEvent $event)
{
if ('The title must be filled' == $event->getData()) {
$event->setData('');
}
},
);
If you want to apply this behavior globally you need to attach this listener using a form type extension that extends 'field'. You will also need to introspect all of the possible validation error messages for the current field using the validator and pass these through the translator, then compare the results with the event data.
Related
I have a TYPO3 php function to get a preselected categories,
The error generated in frontend say that it should be a String but an array is given:
Argument 1 passed to Web\Auf\Controller\ResultsController::getPreselectedCategories() must be of the type string, array given, called in /app/Private/typo3conf/ext/auf/Classes/Controller/DemandRequestTrait.php on line 93
The part of the code called :
protected function getPreselectedStandardCategories(): array
{
return $this->getPreselectedCategories($this->settings['filter']['category']['preselected'] ?? '');
}
Please forgive if this is not clear ask me to explain more or to fix.
Thank you very much for your answers.
The issue was due to wrong Flexform configuration stored in the database,
When the backend user change the type of content element the flexform still stored.
I have deleted the content element and i have created a new one. This fixed my problem.
Am running a form using fluid with two fields, username and password. When first run, correct data is sent to the action. When different data is resubmitted, original data is sent to the controller action instead of the new values. How do I solve this problem?
EDIT: I've discovered that an array containing the user-submitted form fields and their values are obtained from the request, serialized as is and the string stored in a hidden input field called '__referrer[arguments]', which is then submitted with the form back to the user. When the user resubmits the form again with new values, the user doesn't realize that the old values are in the form, in the form of a serialized string, which is submitted together with the new values. Turns out, this is ok if no errors are reported by the validators. In that case the data is simply passed to the controller action and processing continues. But if errors are collected, processing is not sent to the controller action but is sent to the error action. The error action unserializes the old data and forwards that data (instead of the the new values) to the intended action controller. See \TYPO3\CMS\Extbase\Mvc\Controller\ActionController::forwardToReferringRequest().
EDIT: Steps to reproduce;
Create an action with one argument and create a form with one input element and a submit button. Create a validator for the element. Make it a string property. When all is said and done, start by sending a VALID value and let the form return. it will come back with no errors. but also if you look at it's hidden values, you find that the __referrer[arguments] has changes. That's because your previous values were serialized and are there. Now submit an INVALID value and check values entering your action. You'll be stunned they are the old ones.
This is weird. Currently if I disable the production of the __referrer[arguments] input field in the \TYPO3\CMS\Fluid\ViewHelpers\FormViewHelper::renderHiddenReferrerFields() method, everything works properly. How do I solve this? Please help.
Where things go wrong:
Here: \TYPO3\CMS\Extbase\Mvc\Controller\ActionController::forwardToReferringRequest() . In this method, arguments are sought from __referrer internal arguments instead of the submitted values. Normally, if errors are found, only two elements are found in the arguments form variable: controller for controller name and action for action name. This is because they were submitted originally with the form and they will recycle without changing as long as the validator finds errors. Nothing else will be added to it. This is good... until it validates. When it validates, results are sent directly to the action controller and not through the error controller. When the process goes back to the form, the object or arguments submitted will be added to the form and returned to the user. Remember it validated. When you then send a wrong value next, it goes to the error controller, but the old values (that validated) and were serialized in the __referrer[arguments] are unserialized and forwarded to your action. And that's how you end up with old values in your action. This is because it assumes that the variable carries only two values inside it; the controller and action names only. It's wrong.
Assumption:
Form post values processing seem to be built under the presumption that once a form validates, you won't need it again.
News.
The values you send are sought from extbase arguments and serialized in \TYPO3\CMS\Fluid\ViewHelpers\FormViewHelper::renderHiddenReferrerFields() method, added to the form just before presenting it to you. All TYPO3 has to do is skip your values and let the default values only be serialized. Just saw that the doc section of the function has this:
/**
* Renders hidden form fields for referrer information about
* the current controller and action.
*
* #return string Hidden fields with referrer information
* #todo filter out referrer information that is equal to the target (e.g. same packageKey)
*/
The #todo part is the news. Hope it's done in the next-patch since there are many scenarios where you want to resume the form such as in data entry.
Solution
Easiest solution: Initialize the empty argument in your action and hand the argument to the form. In my case, I use a DTO.
Example
public function accountLoginAction(DTO\Account\LoginDTO $accountLogin=null):ResponseInterface
{
if($accountLogin){
$this->repository->logon();
...
} else{
$accountLogin=DTO\Account\LoginDTO::getNewInstance();
}
$this->view->assign('object', $accountLogin);
return $this->response();
}
Hope it helps someone.
This is an odd one. I have this method, that is the callback for the FormEvents::POST_SET_DATA event in an EventSubscriber of a form in Symfony2:
public function preSetData(FormEvent $event)
{
$data = $event->getData();
$form = $event->getForm();
$resource_provider = $data->getResourceProvider();
$type = $resource_provider->getType(); //PROBLEM HERE
\Doctrine\Common\Util\Debug::dump(is_object($resource_provider));
}
It has more code but the error is firing in the line with the comment PROBLEM HERE.
The issue is that the dump there prints bool(true), so it is an object, and have the data inside, but trying to call getType(), that exist, fails with this error:
Error: Call to a member function getType() on a non-object
To add more confusion, if I dump $resource_provider->getType() I get the expected content dumped, but the error remains.
Does someone knows or has a clue on what can be happening here?
EDIT
Can't believe it! I found the answer, but doesn't makes sense at all! I had to wrap the problematic code with a conditional like this:
if(is_a($resource_provider, 'My\Bundle\Path\Entity\ResourceProvider')){}
and it worked! If someone can tell me what is the sense of that, I will happily select his/her answer as correct.
The problem is that $resource_provider is probably null as error says $resource_provider is not an object.
When printing the value of $resource_provider and skipping the script, it shows the right object of class 'My\Bundle\Path\Entity\ResourceProvider' :
echo get_class($resource_provider); exit; // Display My\Bundle\Path\Entity\ResourceProvider and skip the script
When adding a condition to test is the object is of the expected class, the script doesn't crash anymore :
if(is_a($resource_provider, 'My\Bundle\Path\Entity\ResourceProvider')){}
In addition, when skipping script when it's not an object, $resource_provider is null and the script skipped :
if(is_a($resource_provider, 'My\Bundle\Path\Entity\ResourceProvider')){
} else {
var_dump($resource_provider); exit;
}
$resource_provider is an object and null in the same "execution" of the script.
So we can deduce that the EventSubcriber is loaded more than one time, perhaps before the form binding and after form binding for example and the first time with the expected object, and a second (or more) time with no value, as null, perhaps because the $resource_provider is not filled when submitting form or something else.
I have created a doctype in umbraco which has one of the following property:
Property - Case study link
Datatype - Content picker
I need to fetch the URL of this document in a Razor macro and assign it to a hyperlink.
Currently am doing it in this way but it's giving me an error:
#foreach (var item in #Model.OurWork){
Read case study
}
And here is the error I get on viewing the page:
Error loading Razor Script OurWorkGrid.cshtml The best overloaded
method match for 'umbraco.library.NiceUrl(int)' has some invalid
arguments
I have tried outputting the node id without using the niceURL() function and it works fine (outputs 1088).
Read case study
results in this:
Read case study
But as soon as I put back NiceURL() function, it chokes again.
I really don't know what am I doing wrong here!
Instead of using the umbraco library method, try loading the node with the ID first, and then using the Url property to get the nice URL.
#foreach (var item in #Model.OurWork){
var caseStudyNode = #Model.NodeById(item.caseStudyLink);
Read case study
}
Also, add some form of a check to make sure the value is set, in case it's not a mandatory property on the doc type. Here's one example:
if (#item.HasProperty("caseStudyLink") && !string.IsNullOrEmpty(#item.caseStudyLink))
{
...
}
Try something like:
#foreach (var item in #Model.OurWork){
Read case study
}
You may want to check first whether item.caseStudyLink contains a value because this will throw an error otherwise.
How do I submit a form that can do two different things based on the URI?
For example, if the URI contains a string "new" the form will submit differently than it would if "new" were not in the URI.
I'm having trouble implementing this, as when a form is submitted, it takes the URI of whatever "form_open" says.
Altering the form_open path is probably not the way to do this. How are you using this? Does the person filling out the form affect the "new" string?
What I would do is put a hidden input on the form and set THAT value to "new". Then in the controller, use a GET to take the value of the input form, and do a simple IF / ELSE statement based off the value of that variable.
This way, you could setup several different ways to use the same form - hidden=new, hidden=old, hidden=brandnew, hiddend=reallyold could all process the form values differently, even sending them to different tables in your DB or whatever.
Kevin - I thought I'd done something like this before and I had - here's a quick look:
In routes.php:
$route['some/pathname/(:any)'] = "my_controller/my_function/$1";
Then in mycontroller.php:
function my_function($type)
{
if ($type == "new") {
do this }
elseif ($type == "update)" {
do this }
}