Custom validaton messages not working on Symfony 3 - php

I have the following declaration in my user class (Symfony 3, it's an entity class):
/**
* #ORM\Column(type="string", length=128, unique=true)
* #Assert\NotBlank (
* groups={"registration"},
* message = "test"
* )
* #Assert\Email(
* message = "The email '{{ value }}' is not a valid email.",
* groups={"registration"}
* )
*/
private $email;
Everything works fine, except that I can't set a message, instead of my message ('test' for example) a default "This value should not be blank" is displayed.
Yes, I do have
framework:
validation: { enable_annotations: true }
In my config.yml
Edit: and yes I cleared cache by executing:
sudo php bin/console cache:clear
Edit2: Please note that it actually DOES go through validation, Symfony sees that the email is required, it displays a message if I leave the field empty, it's just that it is not my message, Symfony somehow doesn't see the "message" part.
Edit3: Now, after removing the groups={"registration"} part, as well as changing (in controller)
$errors = $validator->validate($user, null, array('registration'));
to
$errors = $validator->validate($user, null);
(removed array('registration'))
the correct message is displayed. However this is not a solution. I need to use groups.
Edit 4:
I'll get crazy...
If I enter no email, and then:
$validator = $this->get('validator');
$errors = $validator->validate($user, null, array('registration'));
dump($errors);
(Notice the "dump" function call) then I see an incorect message displayed on a page (This value should not be blank) but... when I enter the profiler->debug page (the dev tools at the bottom) then I can see that a correct (my) message is there...
Furthermore in profiler->form errors is this incorect message on the list (as only one item) but... it says it refers to a field named "plainPassword" which is not in the form, and does NOT belong to the "registration" group, so it should not be validated in the first place.
What's going on there?

Can You try this?
/**
* #ORM\Column(type="string", length=128, unique=true)
*
*
* #Assert\NotBlank(
* message = "The box cant be left blank")
*
*
* #Assert\Email(
* message = "The email '{{ value }}' is not a valid email."
*
* )
*/
private $email;

Related

Symfony validator conditional validation

* #Assert\Type(type="array")
* #Assert\Count(
* min=5,
* max=10
* )
I need validate a type array and then I need to validate if the array has a min and max count.
But when I send a string value, then Assert\Type evaluates that's not a valid type, but despite that validation continues to Assert\Count and there is problem it is not an array and Assert\Count throw UnexpectedValueException and I have message: This value should be of type {{ type }}., and the that's not the correct validation message for me.
Is possible do Assert\Count only when is Assert\Type condition correct?
If i am understanding your question then using Assert Sequentially is the resolution.
Update your Asserts to look like this:
* #Assert\Sequentially({
* #Assert\Type(type="array"),
* #Assert\Count(min=5, max=10),
* })
*/
The first validation will be raised if your Type is not an array and not perform any further validations.

Internal error due to serialization with paramconverter

I have an API which takes multiple input values. One of them is a date.
When the date is sent, all is fine.
But, when the user isn't sending a date, I have an error 500 with this error message:
Invalid datetime "Some invalid data", expected format Y-m-d\TH:i:sP.
So I wanted to check if the data sent had the format required.
But I don't understand how things are working, hope you can help.
This is what I have
/**
*
* #Rest\Post(
* path = "/signup",
* name = "api_users_add"
* )
* #Rest\View(StatusCode=201, serializerGroups={"user_detail"})
* #ParamConverter(
* "user",
* converter="fos_rest.request_body",
* options={"deserializationContent"={"groups"={"Deserialize"}}},
* )
* #ParamConverter(
* "profile",
* converter="fos_rest.request_body",
* options={"deserializationContent"={"groups"={"Deserialize"}}},
* )
*/
public function postUserAction(Request $request, User $user, Profile $profile)
{
if (!preg_match("^[0-9]{4}-[0-1][0-9]-[0-3][0-9]$",$profile->getBirth())){
return new JsonResponse([
'success' => false,
'message' => "Date d'anniversaire au mauvais format"
]);
}
}
But in fact, I never go into this condition, the error 500 is triggered before.
I guess this has something to do with the #ParamConverter from Profile who can't "deserialize" when birth is not a DateTime.
Thing is, I would like to check what is sent (as I did into my condition) in order to avoid this internal error. But I can't find where this is handled on my code.
Thanks for the help.
Considering this : symfony doc for Param converter fos rest bundle
What I am looking for is to find where the validationErrors are specified.

Symfony validation on multiple file upload

I have a form containing a FileType field. I've set the multiple option to true so the user can upload multiple files at the same time.
$builder->add('myFile', FileType::class, [
'label' => 'upload file',
'multiple' => true,
])
Here is the corresponding property in the Entity connected to this form:
/**
* #Assert\NotBlank()
* #Assert\File(mimeTypes = {"application/pdf", "application/x-pdf", "image/jpeg", "image/png"})
* #ORM\Column(type="array")
*/
private $myFile;
When I submit the form I get the error:
UnexpectedTypeException in FileValidator.php line 168:
Expected argument of type "string", "array" given
I added curly braces in front of File assert so it looks like this:
* #Assert\File{}(mimeTypes = {"application/pdf", "application/x-pdf", "image/jpeg", "image/png"})
Now it doesn't complain when submitting the form. but the file type validation is also not checked.
Any idea how to make the file type working for multiple selected files?
Since you're validating array of File, you need to apply All validator, which will apply inner validators on each element of the array.
Try with something like:
/**
* #Assert\All({
* #Assert\NotBlank(),
* #Assert\File(mimeTypes = {"application/pdf", "application/x-pdf", "image/jpeg", "image/png"})
* })
* #ORM\Column(type="array")
*/
private $myFile;

Symfony Choice assertion message override

I have this assertion inside my entity :
/**
* #Assert\Choice(choices = {"fiction", "non-fiction"}, message = "Choose a valid genre.")
*/
protected $genre;
And the documentation says for the message parameter :
type: string
default: The value you selected is not a valid choice.
This is the message that you will receive if the multiple option is set to false and the underlying value is not in the valid array of choices.
And in my form type, I have :
->add('genre', ChoiceType::class, [
'multiple' => false,
])
But, when the value of gender field isn't in the valid array of choices ("fiction", "non-fiction"), the message error is "This value is not valid."
It isn't not the default value, nor the value I set in the entity.
I know I can override it in the form type with the "invalid_message" parameter,
but I want to if there is an explanation on this ?
Why the "message" parameter oth the Assert/Choice doesn't work?
How can I make it work like its expected in the symfony doc ?
In the docs, it's not speficied that you can pass the possible values in this place.
You need to create a function in the class (for example "getGender()") that returns an array with the valid values.
Then, with the assert, you can call this function like this :
class Author
{
/**
* #Assert\Choice(callback = "getGender", message = "Choose a valid genre.")
*/
protected $genre;
public function getGender() {
return array("fiction", "non-fiction");
}
}
And be carefull, you used "choices" instead of "callback" in the annotation ;)
My first remark would be that
/**
* #Assert\Choice(choices = {"fiction", "non-fiction"}, message = "Choose a valid genre.")
*/
protected $genre;
attribute's name is genre but on the form type you're calling it gender.
I guess this is just mistyping problem.
Just rename the attribute gender instead of genre .

How to properly generate exceptions in PHP/Dojo when returning javascript code

I am having difficulty understanding how exceptions are handled when code is fetched dynamically via AJAX and executed via eval. With clientside javascript, it is rather simple, if I have a piece of code such as this
var j = 'some string';
j.propA.x++;
this will raise an exception because propA, which is of type undefined does not have an x. Furthermore, the exception raised is very easy to understand.
Now lets put the above code in a text file, lets call it test.js, and store it on the server. Now lets load it dynamically with Ajax. I am using the following code to load it dynamically
dojo.xhrGet({
url: 'load.php',
handleAs: "javascript",
content : {
fileName : 'test.js'
},
load: function(returnValue) {
/*Do Something*/
},
error: function(errorMessage) {
/*Report Error*/
}
});
Here is a very basic php script for loading the file and returning it as javascript code
<?php
$fileName = $_GET['fileName'];
$handle = fopen($fileName , 'r');
$script = fread($handle, filesize($fileName));
fclose($handle);
echo $script;
?>
In the above dojo.xhrGet call, the error property can be set to a function to display the error message, here is an example of some of the many ways this can be done.
error: function(errorMessage) {
console.error(errorMessage);
console.error(errorMessage.arguments);
console.error(errorMessage.message);
console.error(errorMessage.stack);
console.error(errorMessage.type);
}
Below is an example of the output. Although this output is for a different problem, it highlights how incomprehensible it is:
Cannot read property 'x' of undefined
TypeError: Cannot read property 'x' of undefined
at eval at <anonymous> (http://o.aolcdn.com/dojo/1.6/dojo/dojo.xd.js:14:3088)
at Object.load (http://192.168.1.8/easel.js:166:6)
at http://o.aolcdn.com/dojo/1.6/dojo/dojo.xd.js:14:89998
at _144 (http://o.aolcdn.com/dojo/1.6/dojo/dojo.xd.js:14:36518)
at _142 (http://o.aolcdn.com/dojo/1.6/dojo/dojo.xd.js:14:36328)
at [object Object].<anonymous> (http://o.aolcdn.com/dojo/1.6/dojo/dojo.xd.js:14:36994)
at _144 (http://o.aolcdn.com/dojo/1.6/dojo/dojo.xd.js:14:36780)
at _142 (http://o.aolcdn.com/dojo/1.6/dojo/dojo.xd.js:14:36328)
at [object Object].<anonymous> (http://o.aolcdn.com/dojo/1.6/dojo/dojo.xd.js:14:36994)
at Object.resHandle (http://o.aolcdn.com/dojo/1.6/dojo/dojo.xd.js:14:92730)
non_object_property_load
I am assuming dojo.xd.js:14 is the line where the eval statement is.
If one knows what they are looking for, the above might suffice. However, is there an easier, or at least a more productive way to deal with exceptions arising in eval?
Here is a somewhat similar question.
Phikin provided a good solution to this problem below so I gave him the bounty. Using his solution, I got an output which looked something like this (I cut it down a bit)
ReferenceError in JS Code detected: (url: module.require.php?module=MainMenu.Bg_S)
easel.js:211Error Message: ReferenceError: apple is not defined
easel.js:213(function(){
return function(args){
dojo.require("Shape");
Module.assert('MainMenu_V');
/**
* The rectangular background of the Main View
* #property MainMenuBg_S
* #type Shape
**/
new Shape({
/**
* Unique descriptive name used when later accessing this shape via '$$()'
* #param name
* #type String
**/
name : 'MainMenu.Bg_S' ,
/**
* Left side of this rectangle
* #param x
* #type Number
**/
x : $$('MainMenu_V').x ,
/**
* Top of this rectangle
* #param y
* #type Number
**/
y : $$('MainMenu_V').y ,
/**
* Width of this rectangle
* #param w
* #type Number
**/
w : $$('MainMenu_V').w ,
/**
* Height of this rectangle
* #param h
* #type Number
**/
h : $$('MainMenu_V').h ,
/**
* Type of this Shape
* #param h
* #type Number
**/
type : shapeType.RECTANGLE ,
/**
* Generate function which contains all the graphics instructions, as well as the contexts
* to preload and initialize. This is currently under development. Backgrounds should NEVER
* have mouse events associated with them as a redraw of a background implies a redraw of
* every single displayObject infront of the background.
* #param generate
* #type method
**/
generate : function (){
var x = this.x << 0 , y = this.y << 0 , h = this.h << 0 , w = this.w << 0 , a = this.a;
this.graphics(contextID.LEAVE).lf([hsl(180,100,60,0.9),hsl(180,100,20,0.75)],[0,1],0,h/2,w,h/2).dr(x,y,w,h).ef();
this.graphics(contextID.ENTER).lf([hsl(135,100,40,0.9),hsl(135,100,20,0.75)],[0,1],0,h/2,w,h/2).dr(x,y,w,h).ef();
this.graphics(contextID.CLICK).lf([hsl(90,100,40,0.9),hsl(90,50,20,0.75)],[0,1],0,h/2,w,h/2).dr(x,y,w,h).ef();
this.graphics(contextID.RCLICK).lf([hsl(90,110,40,0.9),hsl(80,60,20,0.45)],[0,1],0,h/2,w,h/2).dr(x,y,w,h).ef();
this.graphics(contextID.DBLCLICK).lf([hsl(45,100,40,0.9),hsl(45,100,20,0.75)],[0,1],0,h/2,w,h/2).dr(x,y,w,h).ef();
this.graphics(contextID.DBLRCLICK).lf([hsl(10,100,40,0.9),hsl(10,100,20,0.75)],[0,1],0,h/2,w,h/2).dr(x,y,w,h).ef();
this.graphics(contextID.LPRESS).lf([hsl(110,25,40,0.9),hsl(110,25,20,0.75)],[0,1],0,h/2,w,h/2).dr(x,y,w,h).ef();
this.graphics(contextID.RPRESS).lf([hsl(110,50,40,0.9),hsl(110,50,20,0.75)],[0,1],0,h/2,w,h/2).dr(x,y,w,h).ef();
this.graphics(contextID.SCROLL).lf([hsl(110,50,40,0.9),hsl(110,50,20,0.75)],[0,1],0,h/2,w,h/2).dr(x,y,w,h).ef();
if (debugFlags.BOUNDINGBOX()){
this.graphics(contextID.ENTER).ss(2).s(rgba(0,255,0,a)).dr(this.boundingBox.softBounds.L +4<<0, this.boundingBox.softBounds.T +4<<0, this.boundingBox.softBounds.w-8<<0 , this.boundingBox.softBounds.h-8<<0).es();
this.graphics(contextID.ENTER).ss(2).s(rgba(255,0,0,a)).dr(this.boundingBox.bounds.L +4<<0, this.boundingBox.bounds.T +4<<0, this.boundingBox.bounds.w-8<<0 , this.boundingBox.bounds.h-8<<0).es();
this.graphics(contextID.ENTER).f(rgba(0,0,255,a)).dc(this.boundingBox.points[0].x+4 , this.boundingBox.points[0].y+4 , 4).ef();
this.graphics(contextID.ENTER).f(rgba(0,0,255,a)).dc(this.boundingBox.points[1].x-8 , this.boundingBox.points[1].y+4 , 4).ef();
this.graphics(contextID.ENTER).f(rgba(0,0,255,a)).dc(this.boundingBox.points[2].x-8 , this.boundingBox.points[2].y-8 , 4).ef();
this.graphics(contextID.ENTER).f(rgba(0,0,255,a)).dc(this.boundingBox.points[3].x+4 , this.boundingBox.points[3].y-8 , 4).ef();
}
},
/**
* Arguments to pass to the mouse initialization function. These will get mixed in (via
* dojo.mixin) to the mouse object. To increase performance, the signalOrderIn has been set to
* NOHIT. This will limit the number of redraws (remember background redraws are extremely
* expensive as they require redrawing everything in the container). The signalOrderOut is
* then set to BLOCK to prvent anything behind the background from receiving mouse signals
* (this is actually unecessary as the only think behind the background is, and always should
* be, the container, which itself has signalOrderIn and signalOrderOut set to NOHIT and BLOCK
* respectively).
* #param mouse
* #type Object
**/
mouse : {
_signalOrderIN : signalFlags.NOHIT ,
_signalOrderOUT : signalFlags.BLOCK
} ,
/**
* All views are initially loaded via Ajax. Generally, views do not have any preconditions, beyond
* that the stage be present. They can, however, and generally do, have modules they require. These
* are called after this view has been created and loaded (load() function call). They are called
* in the order of the sub arrays. In the example below:
* [[A , B , C , D , E , F , G]]
* The 7 modules are requested in that order, but, due to Ajax, they can be loaded in any order.
* In the below example, on the other hand:
* [[A] , [B , C , D , E , F , G]]
* Modules B-G depend on module A, therefore, module A is ordered to be loaded first.
* #property providedModules
* #type Array[Array[String]]
* #protected
**/
providedModules : [[]] ,
/**
* Carries out all the initializations when loading the module
* #method load
* #protected
**/
load : function (){
0/apple;
$$('MainMenu_V').addChild(this);
} ,
/**
* Carries out all memory deallocation when leaving the module (generally only necessary if modules
* were loaded but not added to stage as in the case with cached bitmaps)
* #method leave
* #protected
**/
leave : function (){
}
});
$$('MainMenu.Bg_S')._code="dojo.require(\"Shape\");...";
};
}());
easel.js:217Error triggered by: function (_2bd){return err.call(args,_2bd,_2b7);}
easel.js:220XHR Object:
easel.js:221
Object
args: Object
handleAs: "javascript"
query: null
url: "module.require.php?module=MainMenu.Bg_S"
xhr: XMLHttpRequest
__proto__: Object
easel.js:222Error Object:
easel.js:223
ReferenceError
arguments: Array[1]
message: "—"
stack: "—"
type: "not_defined"
__proto__: Error
dojo.xd.js:14
ReferenceError
arguments: Array[1]
message: "—"
stack: "—"
type: "not_defined"
__proto__: Error
dojo.xd.js:14
ReferenceError
arguments: Array[1]
message: "—"
stack: "—"
type: "not_defined"
__proto__: Error
The only thing it's missing, that I need, is the ability to indicate what line the problem occurred.
Here is a snipped that detectes non-network related errors from an xhr-get request and outputs some information about it in the console.
There is an extra isEvalError() function that goes through all eval-error types... which I am not really proud of. A nicer way could be by getting the parent object of the errorMessage sub-classes.
I think you can ditch isEvalError() generally, because there shouldn´t be any other error possible in this block.
function isEvalError(errorMessage){
return errorMessage.name == "RangeError" ||
errorMessage.name == "ReferenceError" ||
errorMessage.name == "SyntaxError" ||
errorMessage.name == "URIError" ||
errorMessage.name == "TypeError";
}
var foo = dojo.xhrGet({
url: 'stacko.js',
handleAs: "javascript",
load: function(returnValue) {
console.log("load: "+returnValue);
},
error: function(errorMessage,ioargs) {
//request worked fine, this must be a non-network related error
if(ioargs.xhr.readyState == 4 && ioargs.xhr.status == 200) {
if(isEvalError(errorMessage)){
//show eval-error, url request & the JS code that causes the exception
//eval-error types: RangeError,ReferenceError,SyntaxError, URIError, TypeError
console.error(errorMessage.name+" in JS Code detected: (url: "+ioargs.url+")")
console.error("Error Message: "+ errorMessage);
console.error(ioargs.xhr.responseText);
}
//a little reflection - if u want to know who triggered this error
//(although in this case the output is not very helpful )
console.error("Error triggered by: "+arguments.callee.caller.toString());
//last but not least log the error & the xhr-request object for more information
console.error("XHR Object:");
console.error(ioargs);
console.error("Error Object:");
console.error(errorMessage);
}
}
});
It really depends on what you mean "productive way to deal with exceptions". If all you need to do is view the exception contents, a simple
console.log(errorMessage);
will allow you to effortlessly inspect the error object in decent browser like Chrome or Firefox (with Firebug). (Instead of forcing you to do a ton of console.log statements)
An annoying thing about Dojo exceptions inside asynchronous code is that they are always caught and handled so most browser debuggers ignore them. A notable exception to this rule is Chrome, where you can tell the debugger to pause on all exceptions.
BTW: I don't see how Javascript exceptions and Dojo have anything to do with PHP in this case, since they occur on the client side and there is nothing the server can do about them. Also, what the hell are you doing by sending Javascript code in the AJAX? Most of the time a client does a request it will be for data, in plain text, JSON or XML.

Categories