1
0
mirror of synced 2024-12-15 07:36:03 +03:00
doctrine2/cookbook/en/validation-of-entities.txt

114 lines
4.2 KiB
Plaintext
Raw Normal View History

2010-04-06 22:36:40 +04:00
Doctrine 2 does not ship with any internal validators, the reason being that
2010-10-05 16:09:10 +04:00
we think all the frameworks out there already ship with quite decent ones that can be integrated
2010-04-06 22:36:40 +04:00
into your Domain easily. What we offer are hooks to execute any kind of validation.
> **Note**
> You don't need to validate your entities in the lifecycle events. Its only
> one of many options. Of course you can also perform validations in value setters
> or any other method of your entities that are used in your code.
2010-10-05 16:09:10 +04:00
Entities can register lifecycle event methods with Doctrine that are called on
2010-04-06 22:36:40 +04:00
different occasions. For validation we would need to hook into the
events called before persisting and updating. Even though we don't support
validation out of the box, the implementation is even simpler than in Doctrine 1
and you will get the additional benefit of being able to re-use your validation
in any other part of your domain.
Say we have an `Order` with several `OrderLine` instances. We never want to
allow any customer to order for a larger sum than he is allowed to:
[php]
class Order
{
public function assertCustomerAllowedBuying()
{
$orderLimit = $this->customer->getOrderLimit();
$amount = 0;
foreach ($this->orderLines AS $line) {
$amount += $line->getAmount();
}
if ($amount > $orderLimit) {
throw new CustomerOrderLimitExceededException();
}
}
}
Now this is some pretty important piece of business logic in your code, enforcing
it at any time is important so that customers with a unknown reputation don't
owe your business too much money.
We can enforce this constraint in any of the metadata drivers. First Annotations:
[php]
/**
* @Entity
* @HasLifecycleCallbacks
*/
class Order
{
/**
* @PrePersist @PreUpdate
*/
public function assertCustomerAllowedBuying() {}
}
In XML Mappings:
[xml]
<doctrine-mapping>
<entity name="Order">
<lifecycle-callbacks>
<lifecycle-callback type="prePersist" method="assertCustomerallowedBuying" />
<lifecycle-callback type="preUpdate" method="assertCustomerallowedBuying" />
</lifecycle-callbacks>
</entity>
</doctirne-mapping>
YAML needs some little change yet, to allow multiple lifecycle events for one method,
this will happen before Beta 1 though.
Now validation is performed whenever you call `EntityManager#persist($order)`
or when you call `EntityManager#flush()` and an order is about to be updated.
2010-10-05 16:09:10 +04:00
Any Exception that happens in the lifecycle callbacks will be cached by the
2010-04-06 22:36:40 +04:00
EntityManager and the current transaction is rolled back.
Of course you can do any type of primitive checks, not null, email-validation, string size,
integer and date ranges in your validation callbacks.
[php]
class Order
{
/**
* @PrePersist @PreUpdate
*/
public function validate()
{
if (!($this->plannedShipDate instanceof DateTime)) {
throw new ValidateException();
}
if ($this->plannedShipDate->format('U') < time()) {
throw new ValidateException();
}
if ($this->customer == null) {
throw new OrderRequiresCustomerException();
}
}
}
What is nice about lifecycle events is, you can also re-use the methods at other places
in your domain, for example in combination with your form library.
Additionally there is no limitation in the number of methods you register
on one particular event, i.e. you can register multiple methods for validation in "PrePersist"
or "PreUpdate" or mix and share them in any combinations between those two events.
2010-10-05 16:09:10 +04:00
There is no limit to what you can and can't validate in "PrePersist" and "PreUpdate" as long as
2010-04-06 22:36:40 +04:00
you don't create new entity instances. This was already discussed in the previous
blog post on the Versionable extension, which requires another type of event called "onFlush".
Further readings:
* [Doctrine 2 Manual: Events](http://www.doctrine-project.org/documentation/manual/2_0/en/events#lifecycle-events)