Symfony Validation dependent on another property - symfony

Trying to validate if one field is not empty (length > 0) then the length of the field being validated must be a certain length (2 characters). It seems like an "Assert\Expression" might work in this situation but I am having trouble trying to find the length of the properties. It seems like you cannot call php functions within the Expression. The expression documentation mentions functions but maybe I do not understand it... Do I need to register my own function that simply return a strlen(). If so how do you register your own functions? Can someone explain if there is a way to do this, or maybe there is a better way than using Expression that I am overlooking...
/**
* #var string
*
* #ORM\Column(name="plate", type="string", length=10)
*/
private $plate;
/**
* #var string
*
* #ORM\Column(name="state", type="string", length=2)
* #Assert\Expression(
* "strlen(this.getPlate()) == 0 or (strlen(this.getPlate()) > 0 and strlen(value) == 2)",
* message="Must be 2 characters"
* )
*/
private $state;
In the above case I get an error The function "strlen" does not exist around position 1

Looks like you will need to register your own function. Have a look at the docs: https://symfony.com/doc/current/components/expression_language/extending.html#registering-functions
There is an example on lowercase, strlen should be very similar.
EDIT:
You can also use a callback validator.
/**
* #Assert\Callback()
*/
public function validateState(ExecutionContextInterface $context)
{
if (!empty($this->plate) && mb_strlen($this->state) !== 2) {
$context->buildViolation('State must be 2 characters long')
->atPath('state')
->addViolation();
}
}
But if you are planning to using this kind of validation in multiple places, you can write and register your own validator.

Related

Strange Issue With Entity Relationship in Symfony 4

This is a very odd one, i'll try to explain with couple of sample entities.
class Property{
/**
* #var string
* #ORM\Column(type="string", length=10)
*/
private $postCode;
/**
* #var InstructionToSell
* #ORM\OneToOne(targetEntity="App\Entity\InstructionToSell")
* #ORM\JoinColumn(nullable=true)
*/
private $instructionToSell;
}
class InstructionToSell{
/**
* #var Property
* #ORM\OneToOne(targetEntity="App\Entity\Property")
* #ORM\JoinColumn(nullable=true)
*/
private $property;
}
So two sample entities, the property can have an instruction to sell entity and vice versa. I then have a very basic post code search method in the repo:
/**
* #param string $postCode
* #return array|null
*/
public function searchByPostcode(string $postCode) : ?array{
$builder = $this->createQueryBuilder('p');
$builder->where(
$builder->expr()->like('p.postCode',':postCode')
)->setParameter('postCode',str_replace(' ','','%'.$postCode.'%'));
return $builder->getQuery()->getResult();
}
It all works fine except for one very strange thing. If say a property had the Uk post code of "YO12 7YA" and we run a search for "YO127YA" then it's bringing back a result, but if we use "YO12 7YA" it's bringing back a result but the instructionToSell is null on the property, but it's not null if i remove the space from the search term.
I'm aware this search isn't the best as it stands, need to strip spaces out of the column as well, but the point i am making is, the same code runs for "YO12 7YA" and "YO127YA" which brings back the same property, but one of them has the relationship matched to the instruction to sell, the other it's null.
Why would this happen? It's exactly the same property it's bringing back.

Symfony 4 - Multi assert difficults

in my symfony project I have an entity that has this field:
/**
* Solde
* #ORM\Column(type="float", nullable=true)
*/
private $solde;
This field can be either null, equal to 0 or greater than 0 but can not be negative.
So I wonder how I can organize the asserts for this field?
Can I do something like this?
/**
* #Assert\!Negative
*/
Otherwise the asserts I should use would be:
/ **
* #Assert \ Null ()
* #Assert\GreaterThanOrEqual(0)
* /
But if I use both, it may be a problem because one must make sure that the value is zero, and the other must verify that it is positive or equal to 0
If you are using Symfony 4.3+ you can use PositiveOrZero:
/**
* #Assert\PositiveOrZero
*/
If you combine this with nullable=true, all positive numbers, 0 and null will be valid.
For older versions of Symfony you can use:
/**
* #Assert\GreaterThanOrEqual(0)
*/
Again with nullable=true and you will have the same effect.
or you can create your own validator with its set of logic
enter link description here

Symfony unique integer fields in entity

I have entity with uniq field, inviteCode. And when I create new entity I want set automatic some random code, but this code must be different from exist in db, what do you thing, what practices about that you know ?
/**
* #ORM\Table(name="users")
* #ORM\Entity
* #ORM\HasLifecycleCallbacks
* #AssertBridge\UniqueEntity(
* groups={"registration"},
* fields="inviteCode",
* errorPath="not valid",
* message="This inviteCode is already in use."
* )
*/
class User extends AbstractUser implements UserInterface
{
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(type="string", length=500, unique=true)
* #Annotation\SerializedName("_invite_code")
*/
private $inviteCode;
I found something like that
private function calculateReference($number)
{
$multipliers = array(7,3,1);
$length = strlen($number);
$numberArr = str_split($number);
$sum = 0;
for ($i = $length - 1; $i >= 0; --$i)
{
$sum += $numberArr[$i] * $multipliers[($length - 1 - $i) % 3];
}
return $number.(10 - $sum % 10) % 10;
}
first get max id from table then call function calculateReference with id and then setInviteCode.
But I believe doctrine have something exist for this issue or maybe somebody have good example for this
Someone provided a great answer here https://stackoverflow.com/a/13917309/4173130.
But like he said at the end, you don't need doctrine for such a simple feature. Generating the code in the constructor is an efficient, simple and clear solution.
You can use a UUID library like ramsey/uuid. Then you would be able to generate any random code with Uuid::uuid4();.
Another solution is to use random_bytes() with base64_encode : base64_encode(random_bytes(32)).
Please don't try to create a new function to generate random values. Most of time it is not secure, see https://www.owasp.org/index.php/Insecure_Randomness.
Why not using a uuid? It is included in php as a core function and i believe it suits your needs.
Check in the official documentation here

phpdoc #return value for PHPUnit dataProvider

Is there a phpdoc-compliant way* of expressing the various returned values in a PHPUnit dataProvider?
For example:
return array(
array(false, 17, array(1,2)),
array(true, 19, array(1,2)),
);
I would like to write something more detailed than #return array, that expresses that the first value passed to the test method is a bool, the second is an integer, third is an array (and also what each of these values represent).
* If there's no compliant way, does anyone have tips on how to document in a clear manner?
The only further specification for arrays is what they contain (if always the same type):
/**
* #return array[]
*/
function() {
// ...
}
This annotation expresses the function will return an array of arrays, you can find a further discussion in this question:
PHPDoc type hinting for array of objects?
Note: Not every IDE will be able to interpret it
To a possible clear manner: In my opinion, you can always use code blocks in your comments to explain some of your code:
/**
* returns array with following structure:
* <code>
* array(
* array(
* (bool), (int), (array)
* )
* )
* </code>
*
* #return array[]
*/
Or similar explanation. I'm sure there are plenty ways to give other developers a hint about what to expect. In the end it just needs to be understandable to a human if it is not included in the usual annotations.

Validation in extbase using regex

I want to use validation of model properties in extbase via regex and using the following syntax:
/**
*
*#var string $telephone
*#validate RegularExpression('/^[0-9]+$/')
*/
$protected $telephone;
But I keep getting a validation error, irrespective of the value of $telephone variable.What am I doing wrong?
You could simply do something like
/**
*
* #var string $telephone
*
*/
$protected $telephone;
in this case you only get integer values to var telephone.
the other way is to add the right validation syntax
#validate $telephone notEmpty, regularExpression(regularExpression="/^[0-9]+$/")

Resources