How to create Unique constraint object for form validation? - forms

I need to add the constraints on the fly in the controller action, so I'm doing this:
use Doctrine\Bundle\MongoDBBundle\Validator\Constraints\Unique;
// ...
$form = $this->createFormBuilder($user)
->add('email', 'email', array(
'constraints' => array(
new NotBlank(),
new MinLength(8),
new MaxLength(100),
new Email(),
new Unique(),
),
))
->getForm();
But I get this error:
The options "fields" must be set for constraint Doctrine\Bundle\MongoDBBundle\Validator\Constraints\Unique
I tried passing an array('fields' => 'email') and array('fields' => array('email')) to the constructor but didn't work: Warning: get_class() expects parameter 1 to be object, string given in /home/www/dev/public/pixfeed/vendor/symfony/symfony/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php line 63
So how do I use this class?

The class Doctrine\Bundle\MongoDBBundle\Validator\Constraints\Unique is usually used on the whole Document. E.g.
/**
* #MongoDB\Document(collection="users")
* #MongoDBUnique(fields="email")
*/
class User
Which in my eyes makes a lot more sense on ORM/ODM level, than just check if the users imput is unique.
But if you are force to do it in Form, you could write a custom constraint.

Related

Repository/controller: How can I force TYPO3 to load the field "sorting"?

In a controller/template I'd like to have access to the field sorting of an entity.
I've tried to access it like:
$category->getSorting();
But it fails, as the method does not exist. When I dump the entity, all those meta fields, like hidden, starttime etc. aren't listed at all.
How can I tell TYPO3 to load those fields along with the other fields of the entitiy?
Since you are in Extbase context, you have to add the property to your model or (if you use the model of another extension) extend it and add the property. In both cases a getter and a setter method is needed if you want to access and edit the properties value:
/**
* #var integer
*/
protected $sorting;
public function setSorting($sorting) {
$this->sorting = $sorting;
}
public function getSorting() {
return $this->sorting;
}
Make sure you have that field configured in the TCA as well:
...
'columns' => array(
'sorting' => array(
'label' => 'sorting',
'config' => array(
'type' => 'passthrough'
)
),
...
After this you should be able to access the sorting property.

Add validation constraints on mapped = false fields for a specific validation group

I'd like to be able to add in a Form class additional validation constraints for a specific validation group. How could I do that ?
Since Symfony 2.1, adding a validation while building the form looks like this :
use Symfony\Component\Validator\Constraints\MinLength;
use Symfony\Component\Validator\Constraints\NotBlank;
$builder
->add('firstName', 'text', array(
'constraints' => new MinLength(3),
))
->add('lastName', 'text', array(
'constraints' => array(
new NotBlank(),
new MinLength(3),
),
))
;
sources
Is there a way to assign them to a validation constraint ?
In my case, I have validation groups depending on submitted data
Thanks in advance for your suggestions
OK, well the solution was pretty straighforward actually.
Looking at the Constraint class, I noticed the exposed $groups property and addImplicitGroupName(string $group) method.
When you know that, you know all about it:
$cv1 = new NotBlank();
$cv1->groups = array('myGroup');
$cv2 = new NotNull();
$cv2->groups = array('myGroup');
$myCnstrs = array(
'constraints' => array(
$cv1,
$cv2,
)
);
$myOtherOptions = array(
...
);
$builder->add('myField', null, array_merge($myCnstrs,$myOtherOptions));
Sorry if I abused by posting a question and replying to it right after...

Symfony 2. How I can set default values to embedded forms from entities?

I need to set default values for my form. There is code, from my controller:
$form = $this->createFormBuilder()->add('user', new Form\UserType($user))
->add('client', new Form\ClientType($client))
->getForm();
And I have two entites: User & Client. So, how I can set default values from entites?
I set the default values for my text fields like this
->add('firstname', 'text', array('attr' => array('value' => 'bla')))
for an Entity you can set empty value to false and fill the prefrred_choices array
->add('language', 'entity', array('empty_value' => false, 'preferred_choices' => array('2'), 'class' => 'CPAppUserBundle:Language', ))
In the form classes of each your user and your client class you can set default values like this:
public function configure() {
$this->setDefault('yourfield', $defaultvalue);
}

Zend_Validate_Db_RecordExists against 2 fields

I usualy use Zend_Validate_Db_RecordExists to update or insert a record. This works fine with one field to check against. How to do it if you have two fields to check?
$validator = new Zend_Validate_Db_RecordExists(
array(
'table' => $this->_name,
'field' => 'id_sector,day_of_week'
)
);
if ($validator->isValid($fields_values['id_sector'],$fields_values['day_of_week'])){
//true
}
I tried it with an array and comma separated list, nothing works... Any help is welcome.
Regards
Andrea
To do this you would have to extend the Zend_Validate_Db_RecordExists class.
It doesn't currently know how to check for the existence of more than one field.
You could just use two different validator instances to check the two fields separately. This is the only work around that I can see right now besides extending it.
If you choose to extend it then you'll have to find some way of passing in all the fields to the constructor ( array seems like a good choice ), and then you'll have to dig into the method that creates the sql query. In this method you'll have to loop over the array of fields that were passed in to the constructor.
You should look into using the exclude parameter. Something like this should do what you want:
$validator = new Zend_Validate_Db_RecordExists(
array(
'table' => $this->_name,
'field' => 'id_sector',
'exclude' => array(
'field' => 'day_of_week',
'value' => $fields_values['day_of_week']
)
);
The exclude field will effectively add to the automatically generated WHERE part to create something equivalent to this:
WHERE `id_sector` = $fields_values['id_sector'] AND `day_of_week` = $fields_values['day_of_week']
Its kind of a hack in that we're using it for the opposite of what it was intended, but its working for me similar to this (I'm using it with Db_NoRecordExists).
Source: Zend_Validate_Db_NoRecordExists example
Sorry for the late reply.
The best option that worked for me is this:
// create an instance of the Zend_Validate_Db_RecordExists class
// pass in the database table name and the first field (as usual)...
$validator = new Zend_Validate_Db_RecordExists(array(
'table' => 'tablename',
'field' => 'first_field'
));
// reset the where clause used by Zend_Validate_Db_RecordExists
$validator->getSelect()->reset('where');
// set again the first field and the second field.
// :value is a named parameter that will be substituted
// by the value passed to the isValid method
$validator->getSelect()->where('first_field = ?', $first_field);
$validator->getSelect()->where('second_field = :value', $second_field);
// add your new record exist based on 2 fields validator to your element.
$element = new Zend_Form_Element_Text('element');
$element->addValidator($validator);
// add the validated element to the form.
$form->addElement($element);
I hope that will help someone :)
Although, I would strongly recommend a neater solution which would be to extend the Zend_Validate_Db_RecordExists class with the above code.
Enjoy!!
Rosario
$dbAdapter = Zend_Db_Table::getDefaultAdapter();
'validators' => array('EmailAddress', $obj= new Zend_Validate_Db_NoRecordExists(array('adapter'=>$dbAdapter,
'field'=>'email',
'table'=>'user',
'exclude'=>array('field'=>'email','value'=>$this->_options['email'], 'field'=>'is_deleted', 'value'=>'1')
))),
For those using Zend 2, If you want to check if user with given id and email exists in table users, It is possible this way.
First, you create the select object that will be use as parameter for the Zend\Validator\Db\RecordExists object
$select = new Zend\Db\Sql\Select();
$select->from('users')
->where->equalTo('id', $user_id)
->where->equalTo('email', $email);
Now, create RecordExists object and check the existence this way
$validator = new Zend\Validator\Db\RecordExists($select);
$validator->setAdapter($dbAdapter);
if ($validator->isValid($username)) {
echo 'This user is valid';
} else {
//get and display errors
$messages = $validator->getMessages();
foreach ($messages as $message) {
echo "$message\n";
}
}
This sample is from ZF2 official doc
You can use the 'exclude' in this parameter pass the second clause that you want to filter through.
$clause = 'table.field2 = value';
$validator = new Zend_Validate_Db_RecordExists(
array(
'table' => 'table',
'field' => 'field1',
'exclude' => $clause
)
);
if ($validator->isValid('value') {
true;
}
I am using zend framework v.3 and validation via InputFilter(), it uses same validation rules as zend framework 2.
In my case I need to check, if location exists in db (by 'id' field) and has needed company's id ('company_id' field).
I implemented it in next way:
$clause = new Operator('company_id', Operator::OP_EQ, $companyId);
$inputFilter->add([
'name' => 'location_id',
'required' => false,
'filters' => [
['name' => 'StringTrim'],
['name' => 'ToInt'],
],
'validators' => [
[
'name' => 'Int',
],
[
'name' => 'dbRecordExists',
'options' => [
'adapter' => $dbAdapterCore,
'table' => 'locations',
'field' => 'id',
'exclude' => $clause,
'messages' => [
'noRecordFound' => "Location does not exist.",
],
]
],
],
]);
In this case validation will pass, only if 'locations' table has item with columns id == $value and company_id == $companyId, like next:
select * from location where id = ? AND company_id = ?

Zend_Framework: Pass array options to a custom filter

I do not understand how I can send an array with options to my custom filter. Can you please help me?
class Core_Filter_MyFilter implements Zend_Filter_Interface
{
public function __construct($options = null)
...
}
class Blog_Form_Comment extends Zend_Form
{
public function init()
{
$this->setMethod('post');
$this->addElementPrefixPath('Core_Filter', 'Core/Filter/', 'filter');
$this->addElement('textarea', 'entry', array(
'filters' => array(MyFilter)));
I have tried several different ways and I have only managed to send a string as a option to the constructor, but I need to be able to send an array.
Instead of relying on the PluginLoader to load your filter class from the string name representation, you can pass an instance of your filter directly to the element.
$this->addElement('textarea', 'entry', array(
'filters' => array(new Core_Filter_MyFilter($filterOptions))
));
This works with the addFilter() method as well.
Also, while it is not mentioned in the Reference Manual, filters support a similar syntax to validators. So, utilizing the plugin loader, you can use the short name, and an array of arguments to pass to the constructor, like so:
$this->addElement('textarea', 'entry', array(
'filters' => array(
array('MyFilter', array($filterOptions)
)
));
However, note that relying on the plugin loader in this fashion can produce unnecessary overhead if you are in a performance critical situation. The form element relies on PHP's reflection system to create the filter instance and pass it your options. PHP's runtime reflection is not exactly known for speed. This may or may not be a micro/premature optimization, and I'm not suggesting either way, just listing the relevant caveats.
The Zend_Form_Element::addFilters() function can help you understand this process a bit.
The array passed contains one filter per element. If that element is a string or an instanceof Zend_Filter_Interface it passes it along to addFilter() with no 'options'
If the element is an array, the first element of that becomes the filter name, the second element becomes the options. The options array is used in _loadFilter() which passes the options array to the constructor of the filter. An example of using a PregReplace filter:
// Zend_Filter_PregReplace::__construct($matchPattern = null, $replacement = null)
$this->addElement('textarea', 'entry', array(
'filters' => array(
array('PregReplace', array('/test/', 'passed'))
),
);
// equivalent to:
$this->addElement('textarea', 'entry', array(
'filters' => array(
new Zend_Filter_PregReplace('/test', 'passed');
),
);
If you want to pass an array as a first argument, you'll need to wrap it in another array:
$this->addElement('textarea', 'entry', array(
'filters'=>array(
array('MyFilter', array(array(
'option1'=>'test',
'option2'=>'test',
))),
),
);