Skip to content
This repository was archived by the owner on Jan 31, 2020. It is now read-only.

Commit e79f817

Browse files
committed
Merge branch 'hotfix/45'
Close #45
2 parents 9ccac57 + 9fec69f commit e79f817

9 files changed

+930
-0
lines changed
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
# AggregateHydrator
2+
3+
`Zend\Stdlib\Hydrator\Aggregate\AggregateHydrator` is an implementation of
4+
`Zend\Stdlib\Hydrator\HydratorInterface` that composes multiple hydrators via event listeners.
5+
6+
You typically want to use an aggregate hydrator when you want to hydrate or extract data from
7+
complex objects that implement multiple interfaces, and therefore need multiple hydrators to handle
8+
that in subsequent steps.
9+
10+
## Installation requirements
11+
12+
The `AggregateHydrator` is based on the `Zend\EventManager` component, so be sure to have it
13+
installed before getting started:
14+
15+
```php
16+
php composer.phar require zendframework/zend-eventmanager:2.*
17+
```
18+
19+
## Basic usage
20+
21+
A simple use case may be hydrating a `BlogPost` object, which contains data for the user that
22+
created it, the time it was created, the current publishing status, etc:
23+
24+
```php
25+
use Zend\Stdlib\Hydrator\Aggregate\AggregateHydrator;
26+
27+
$hydrator = new AggregateHydrator();
28+
29+
// attach the various hydrators capable of handling simpler interfaces
30+
$hydrator->add(new My\BlogPostHydrator());
31+
$hydrator->add(new My\UserAwareObjectHydrator());
32+
$hydrator->add(new My\TimestampedObjectHydrator());
33+
$hydrator->add(new My\PublishableObjectHydrator());
34+
// ...
35+
36+
// Now retrieve the BlogPost object
37+
// ...
38+
39+
// you can now extract complex data from a blogpost
40+
$data = $hydrator->extract($blogPost);
41+
42+
// or you can fill the object with complex data
43+
$blogPost = $hydrator->hydrate($data, $blogPost);
44+
```
45+
46+
> ## Note
47+
#### Hydrator priorities
48+
`AggregateHydrator::add` has a second optional argument `$priority`. If you have two or more
49+
hydrators that conflict with each other for same data keys, you may decide which one has to be
50+
executed first or last by passing a higher or lower integer priority to the second argument of
51+
`AggregateHydrator::add`
52+
53+
In order to work with this logic, each of the hydrators that are attached should just ignore any
54+
unknown object type passed in, such as in following example:
55+
56+
```php
57+
namespace My;
58+
59+
use Zend\Stdlib\Hydrator\HydratorInterface
60+
61+
class BlogPostHydrator implements HydratorInterface
62+
{
63+
public function hydrate($data, $object)
64+
{
65+
if (!$object instanceof BlogPost) {
66+
return $object;
67+
}
68+
69+
// ... continue hydration ...
70+
}
71+
72+
public function extract($object)
73+
{
74+
if (!$object instanceof BlogPost) {
75+
return array();
76+
}
77+
78+
// ... continue extraction ...
79+
}
80+
}
81+
```
82+
83+
## Advanced use cases
84+
85+
Since the `AggregateHydrator` is event-driven, you can use the `EventManager` API to tweak its
86+
behaviour.
87+
88+
Common use cases are:
89+
90+
> - Removal of hydrated data keys (passwords/confidential information) depending on business rules
91+
- Caching of the hydration/extraction process
92+
- Transformations on extracted data, for compatibility with third-party APIs
93+
94+
In the following example, a cache listener will be introduced to speed up hydration, which can be
95+
very useful when the same data is requested multiple times:
96+
97+
```php
98+
use Zend\Stdlib\Hydrator\Aggregate\AggregateHydrator;
99+
use Zend\Stdlib\Hydrator\Aggregate\ExtractEvent;
100+
use Zend\Cache\Storage\Adapter\Memory;
101+
102+
$hydrator = new AggregateHydrator();
103+
104+
// attach the various hydrators
105+
$hydrator->add(new My\BlogPostHydrator());
106+
$hydrator->add(new My\UserAwareObjectHydrator());
107+
$hydrator->add(new My\TimestampedObjectHydrator());
108+
$hydrator->add(new My\PublishableObjectHydrator());
109+
// ...
110+
111+
$cache = new Memory();
112+
$cacheReadListener = function (ExtractEvent $event) use ($cache) {
113+
$object = $event->getExtractionObject();
114+
115+
if (!$object instanceof BlogPost) {
116+
return;
117+
}
118+
119+
if ($cache->hasItem($object->getId())) {
120+
$event->setExtractedData($cache->getItem($object->getId()));
121+
$event->stopPropagation();
122+
}
123+
};
124+
$cacheWriteListener = function (ExtractEvent $event) use ($cache) {
125+
$object = $event->getExtractionObject();
126+
127+
if (!$object instanceof BlogPost) {
128+
return;
129+
}
130+
131+
$cache->setItem($object->getId(), $event->getExtractedData());
132+
};
133+
134+
// attaching a high priority listener executed before extraction logic
135+
$hydrator->getEventManager()->attach(ExtractEvent::EVENT_EXTRACT, $cacheReadListener, 1000);
136+
// attaching a low priority listener executed after extraction logic
137+
$hydrator->getEventManager()->attach(ExtractEvent::EVENT_EXTRACT, $cacheWriteListener, -1000);
138+
```
139+
140+
With an aggregate hydrator configured in this way, any `$hydrator->extract($blogPost)` operation
141+
will be cached

0 commit comments

Comments
 (0)