-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Images][Taxon] Validation for unique code during creation/edition #6311
Conversation
tuka217
commented
Oct 5, 2016
•
edited
Loading
edited
Q | A |
---|---|
Bug fix? | yes |
New feature? | yes |
BC breaks? | no |
Related tickets | - |
License | MIT |
public function validate($images, Constraint $constraint) | ||
{ | ||
/** @var ImageInterface[] $imagesFromDatabase */ | ||
$imagesFromDatabase = $this->resourceRepository->findAll(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Getting all of them will be sloooooooooow.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can filter them by owner.
|
||
/** @var ImageInterface[] $images */ | ||
foreach ($images as $key => $image) { | ||
foreach ($imagesFromDatabase as $imageFromDatabase) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
$images
-> $newImages
$imagesFromDatabase
-> $persistedImages
?
foreach ($images as $key => $image) { | ||
foreach ($imagesFromDatabase as $imageFromDatabase) { | ||
if ($imageFromDatabase->getOwner() === $image->getOwner() && $imageFromDatabase->getCode() === $image->getCode()) { | ||
$this->context->addViolationAt(sprintf('[%d].code', $key), $constraint->message); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addViolationAt
is deprecated, we should use buildViolation($message)->atPath($path)->addViolation()
.
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function validate($images, Constraint $constraint) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Btw. isn't something like that enough? Do we even need to use the repository?
$imagesCodesUsage = array_count_values(array_map(function (ImageInterface $image) {
return $image->getCode();
}, $images));
$duplicatedImages = array_filter($images, function (ImageInterface $image) use ($imagesCodesUsage) {
return $imagesCodesUsage[$image->getCode()] > 1;
});
foreach (array_keys($duplicatedImages) as $key) {
$this->context->addViolationAt(sprintf('[%d].code', $key), $constraint->message);
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But first step return an warning which stopped a work of validator. And second one too.
ImageInterface $secondImage, | ||
ImageInterface $thirdImage, | ||
ImageAwareInterface $owner, | ||
ImageUniqueCode $constraint, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should use new
to create it inside spec, mocking constraint gives us no profit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What kind of profit gives creating new constraint? It has only an message.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An message which is null
while mocking it :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But message can be any string. In fact it should be argument with type string
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup, my bad, mocking does indeed preserve the properties value (but does not run the constructor).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And ok, it should be create by new. But not because that the message is null, but more because the kind of instance of ImageUnigeCode does not metter.
$secondImage->getOwner()->willReturn($owner); | ||
|
||
$firstImage->getCode()->willReturn('car'); | ||
$secondImage->getCode()->willReturn('car'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is second image even used in this spec?
ImageInterface $thirdImage, | ||
ImageAwareInterface $owner, | ||
ImageUniqueCode $constraint, | ||
RepositoryInterface $imageRepository |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be the first argument as it's injected to the constructor.
29347b1
to
fccd564
Compare
@tuka217 Is it still a WIP? |
Yups, 5 minutes. |
fccd564
to
4d82c5e
Compare
$this->context->addViolationAt(sprintf('[%d].code', $key), $constraint->message); | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we don't have to check the owner, as we always receive collection of images of a single "owner". The following implementation would be simpler:
$imagesCodes = [];
/** @var ImageInterface[] $images */
foreach ($images as $key => $image) {
if (array_key_exists($imagesCodes[$image->getCode()])) {
$this->context->addViolationAt(sprintf('[%d].code', $key), $constraint->message);
}
$imagesCodes[$image->getCode()] = $image;
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It won't add the violation to a first element with duplicate code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about the following?
$imagesCodes = [];
/** @var ImageInterface[] $images */
foreach ($images as $key => $image) {
if (!array_key_exists($imagesCodes[$image->getCode()])) {
$imagesCodes[$image->getCode()] = $key;
continue;
}
$this->context->addViolationAt(sprintf('[%d].code', $key), $constraint->message);
if (false !== $imagesCodes[$image->getCode()]) {
$this->context->addViolationAt(sprintf('[%d].code', $imagesCodes[$image->getCode()]), $constraint->message);
$imagesCodes[$image->getCode()] = false;
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It will be faster than filtering?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Filtering is like for
loop, so for each image you iterate over all images and the complexity is exponential O(n^2), so for 10 images we have 100 iterations (10*10). With the above code the complexity is linear O(n), so we would have only 10 iterations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Solution with "filter" has only two loops, so if you want the more readable solution I would chose this. But, please decide which one will be the best, because it the 5th change for this simple class which (btw) will be evolved in the future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Considering only collection of images it should never be so big that the complexity will influence the performance in any noticeable way, so I'm for @pamil's solution as it's clean and easy to understand. When there will be use cases for bigger collections and performance issues we can provide less complex solution.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tuka217 the current solution is readable but doesn't assign validation error to the first image with duplicated code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's assign, but I changed it do your solution and please, leave it in this form. It's not so hard to understand what this method do.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tuka217 I hate this new Github interface! My comment was to the old implementation because I didn't see the updated code... 😕
c6d4e24
to
502c124
Compare
502c124
to
8c0597d
Compare
Thank you Ania, good job! ;) |