Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 481 lines (378 sloc) 14.833 kB
1bfb208 @mariano README updates
authored
1 li3\_doctrine2 offers integration between [the most RAD PHP framework] [lithium]
b7bce75 @mariano Adding README
authored
2 and possibly the best PHP 5.3 ORM out there: [Doctrine2] [doctrine2]
3
4 # License #
5
1bfb208 @mariano README updates
authored
6 li3\_doctrine2 is released under the [BSD License] [license].
b7bce75 @mariano Adding README
authored
7
8 # Installation #
9
1bfb208 @mariano README updates
authored
10 It is recommended that you install li3\_doctrine2 as a GIT submodule, in order
b7bce75 @mariano Adding README
authored
11 to keep up with the latest upgrades. To do so, switch to the core directory
12 holding your lithium application, and do:
13
14 ```bash
a6ef188 @mariano Recommending installation on main library folder
authored
15 $ git submodule add https://github.com/mariano/li3_doctrine2.git libraries/li3_doctrine2
16 $ cd libraries/li3_doctrine2 && git submodule update --init
b7bce75 @mariano Adding README
authored
17 $ cd _source/doctrine2 && git submodule update --init
18 ```
19
1bfb208 @mariano README updates
authored
20 # Usage #
21
b9bef23 @mariano README updates
authored
22 ## Adding the li3\_doctrine2 library ##
1bfb208 @mariano README updates
authored
23
a6ef188 @mariano Recommending installation on main library folder
authored
24 Once you have downloaded li3\_doctrine2 and placed it in your main `libraries`
25 folder, or your `app/libraries` folder, you need to enable it by placing the
26 following at the end of your `app/config/bootstrap/libraries.php` file:
1bfb208 @mariano README updates
authored
27
28 ```php
29 Libraries::add('li3_doctrine2');
30 ```
31
32 ## Defining a connection ##
33
b9bef23 @mariano README updates
authored
34 Setting up a connection with li3\_doctrine2 is easy. All you need to do is
35 add the following to your `app/config/bootstrap/connections.php` file (make
36 sure to edit the settings to match your host, without altering the `type`
37 setting):
38
39 ```php
40 Connections::add('default', array(
41 'type' => 'Doctrine',
42 'driver' => 'pdo_mysql',
43 'host' => 'localhost',
44 'user' => 'root',
45 'password' => 'password',
707fc8e @mariano Documentation updates
authored
46 'dbname' => 'my_db'
b9bef23 @mariano README updates
authored
47 ));
48 ```
1bfb208 @mariano README updates
authored
49
707fc8e @mariano Documentation updates
authored
50 ## Working with models ##
51
52 ### Creating models ###
1bfb208 @mariano README updates
authored
53
54 When looking to create your doctrine models, you have two choices: you can
889e90b @mariano Documentation updates
authored
55 have them follow your custom class hierarchy (or none at all), or you could
1bfb208 @mariano README updates
authored
56 have them extend from the `BaseEntity` class provided by this library. The
b9bef23 @mariano README updates
authored
57 advantage of choosing the later is that your models will have lithium's
889e90b @mariano Documentation updates
authored
58 validation support, and can be better integrated with the custom adapters
59 provided by this library (such as for session management or for authorization.)
b9bef23 @mariano README updates
authored
60
61 Let us create a `User` model. Following doctrine's [basic mapping guide]
72f1e8b @mariano Documentation updates
authored
62 [doctrine-mapping-guide] we'll use annotations to define the properties, and
63 we will also include lithium validation rules (that's why we are choosing to
64 extend this model from `BaseEntity`):
b9bef23 @mariano README updates
authored
65
66 ```php
72f1e8b @mariano Documentation updates
authored
67 <?php
68 namespace app\models;
69
70 use Doctrine\ORM\Mapping\Column;
71 use Doctrine\ORM\Mapping\Entity;
72 use Doctrine\ORM\Mapping\GeneratedValue;
73 use Doctrine\ORM\Mapping\Id;
74 use Doctrine\ORM\Mapping\Table;
75 use lithium\security\Password;
76
77 /**
78 * @Entity
79 * @Table(name="users")
80 */
81 class User extends \li3_doctrine2\models\BaseEntity {
82 /**
83 * @Id
84 * @GeneratedValue
85 * @Column(type="integer")
86 */
5e3b410 @mariano Documentation updates
authored
87 private $id;
72f1e8b @mariano Documentation updates
authored
88
89 /**
90 * @Column(type="string",unique=true)
91 */
5e3b410 @mariano Documentation updates
authored
92 private $email;
72f1e8b @mariano Documentation updates
authored
93
94 /**
95 * @Column(type="text")
96 */
5e3b410 @mariano Documentation updates
authored
97 private $password;
72f1e8b @mariano Documentation updates
authored
98
99 /**
100 * @Column(type="string")
101 */
5e3b410 @mariano Documentation updates
authored
102 private $name;
72f1e8b @mariano Documentation updates
authored
103
104 /**
105 * Validation rules
106 */
f6dc2ee @mariano Only mapped fields need to be protected
authored
107 protected $validates = array(
72f1e8b @mariano Documentation updates
authored
108 'email' => array(
109 'required' => array('notEmpty', 'message' => 'Email is required'),
110 'valid' => array('email', 'message' => 'You must specify a valid email address', 'skipEmpty' => true)
111 ),
112 'password' => array('notEmpty', 'message' => 'Password must not be blank'),
113 'name' => array('notEmpty', 'message' => 'Please provide your full name')
114
115 );
116
117 public function getId() {
118 return $this->id;
119 }
120
121 public function getEmail() {
122 return $this->email;
123 }
124
125 public function setEmail($email) {
126 $this->email = $email;
127 }
128
96bca82 @mariano Adding note to README
authored
129 public function getPassword() {
130 return $this->password;
131 }
132
72f1e8b @mariano Documentation updates
authored
133 public function setPassword($password) {
134 $this->password = !empty($password) ? Password::hash($password) : null;
135 }
136
137 public function getName() {
138 return $this->name;
139 }
140
141 public function setName($name) {
142 $this->name = $name;
143 }
144 }
145 ?>
b9bef23 @mariano README updates
authored
146 ```
1bfb208 @mariano README updates
authored
147
96bca82 @mariano Adding note to README
authored
148 You should note that if you make your model properties private, each property
2bc7b6e @mariano README improvement
authored
149 **must have** a getter and a setter method, otherwise validation and other
96bca82 @mariano Adding note to README
authored
150 features provided by `BaseEntity` won't work.
151
889e90b @mariano Documentation updates
authored
152 ### Using the Doctrine shell to generate the schema ###
707fc8e @mariano Documentation updates
authored
153
623f2ae @mariano Documentation updates
authored
154 Once you have your model(s) created, you can use doctrine's shell to generate
155 the schema. li3\_doctrine2 offers a wrapper for doctrine's shell that
889e90b @mariano Documentation updates
authored
156 reutilizes lithium's connection details. To run the access the core directory
157 of your application and do:
623f2ae @mariano Documentation updates
authored
158
159 ```bash
a6ef188 @mariano Recommending installation on main library folder
authored
160 $ libraries/li3_doctrine2/bin/doctrine
623f2ae @mariano Documentation updates
authored
161 ```
162
163 That will give you all the available commands. For example, to get the SQL
164 you should run to create the schema for your models, do:
165
166 ```bash
a6ef188 @mariano Recommending installation on main library folder
authored
167 $ libraries/li3_doctrine2/bin/doctrine orm:schema-tool:create --dump-sql
623f2ae @mariano Documentation updates
authored
168 ```
169
170 which will give an output similar to the following:
171
172 ```sql
173 CREATE TABLE users (
174 id INT AUTO_INCREMENT NOT NULL,
175 email VARCHAR(255) NOT NULL,
176 password LONGTEXT NOT NULL,
177 name VARCHAR(255) NOT NULL,
178 UNIQUE INDEX UNIQ_1483A5E9E7927C74 (email),
179 PRIMARY KEY(id)
180 ) ENGINE = InnoDB
181 ```
707fc8e @mariano Documentation updates
authored
182
889e90b @mariano Documentation updates
authored
183 ### Getting the entity manager ###
184
185 Doctrine's `EntityManager` is the way we have to interact with the underlying
186 database, which means we'll always need to obtain it. You can do so by
187 running the following code (change `default` to the name of your connection
188 as defined in `app/config/connections.php`):
189
190 ```php
191 $em = \lithium\data\Connections::get('default')->getEntityManager();
192 ```
193
194 If your models extend from `BaseEntity`, then all of them have a static method
195 named `getEntityManager()` (which uses a static property inherited from
196 `BaseEntity` named `$connectionName` to figure out what connection to use):
197
198 ```php
199 $em = User::getEntityManager();
200 ```
201
202 ### Fetching records ###
203
204 Once you have the entity manager, you can fetch a user with ID 1 (notice how
205 we use the fully qualified class name for the model) using the entity
206 manager:
207
208 ```php
209 $user = $em->find('app\models\User', 1);
210 ```
211
212 or using model repositories:
213
214 ```php
215 $user = $em->getRepository('app\models\User')->findOneById(1);
216 ```
217
218 If you want to find out more about querying models with Doctrine, go through
219 its [Querying guide] [doctrine-querying-guide].
220
221 ### Creating/Updating/Deleting records ###
222
223 Records are persisted (or removed) though the entity manager, as shown in
224 Doctrine's [Persisting guide] [doctrine-persisting-guide].
225
226 One thing to note is that if your models extend from `BaseEntity`, you have
227 validation rules defined for them, and the data you provide does not validate,
228 persisting it will throw a `ValidateException` (the following example uses
229 the `User` model we defined earlier):
230
231 ```php
232 $user = new User();
233 $user->setName('John Doe');
234 $user->setEmail('bademail@');
235
236 try {
237 $em->persist($user);
238 $em->flush();
239 } catch(\li3_doctrine2\models\ValidateException $e) {
240 echo $e->getMessage();
241 }
242 ```
243
244 You should also note that `BaseEntity` provides a method named `set()` which
245 comes very handy if the user data is to be populated from a form submission.
246 If so, the above code could be rewritten as:
247
248 ```php
249 $user = new User();
250 $user->set($this->request->data);
251
252 try {
253 $em->persist($user);
254 $em->flush();
255 } catch(\li3_doctrine2\models\ValidateException $e) {
256 echo $e->getMessage();
257 }
258 ```
259
260 In this last example, if lithium's form helper is bound to the record instance,
261 it will properly show validation errors. The following view code uses the
262 `$user` variable from the example above to bind the form to its validation
263 errors:
264
265 ```php
266 <?php echo $this->form->create(isset($user) ? $user : null); ?>
267 <?php echo $this->form->field('email'); ?>
268 <?php echo $this->form->field('password', array('type' => 'password')); ?>
269 <?php echo $this->form->field('name'); ?>
270 <?php echo $this->form->submit('Signup'); ?>
271 <?php echo $this->form->end(); ?>
272 ```
273
dcc154b @mariano Documentation updates
authored
274 # Extensions #
275
276 li3\_doctrine2 also offers a set of extensions to integrate different parts
277 of your application with your doctrine models.
278
279 ## Session ##
280
281 Some installations require session data to be stored on a centralized location.
282 While there are powerful, storage-centric solutions for session storage, using
283 the database is still a popular choice.
284
285 If you wish to store your session data on the database, using Doctrine models,
286 then you will need to use li3\_doctrine2's session adapter. You start by
287 creating the model that the library will use to represent a session record.
288 For example, create a file named `Session.php` and place it in your
289 `app/models` folder with the following contents:
290
291 ```php
292 <?php
293 namespace app\models;
294
295 /**
296 * @Entity
297 * @Table(name="sessions")
298 */
299 class Session extends \li3_doctrine2\models\BaseSession {
300 }
301 ?>
302 ```
303
304 We are extending from `BaseSession` since it provides us with the needed
305 methods the session adapter will expect it to have. Remember to create the
306 schema for this model.
307
308 The final step is configuring the session. Edit your
309 `app/config/bootstrap/session.php` file and use the following to configure the
310 session:
311
312 ```php
313 Session::config(array(
314 'default' => array(
315 'adapter' => 'li3_doctrine2\extensions\adapter\session\Entity',
316 'model' => 'app\models\Session'
317 )
318 ));
319 ```
320
321 If you wish to override session INI settings, use the `ini` setting. For
322 example, if you wish your session data to be valid across all subdomains,
323 replace the session definition with the following:
324
325 ```php
326 $host = $_SERVER['HTTP_HOST'];
327 if (strpos($host, '.') !== false) {
328 $host = preg_replace('/^.*?([^\.]+\.[^\.]+)$/', '\\1', $host);
329 }
330 Session::config(array(
331 'default' => array(
332 'adapter' => 'li3_doctrine2\extensions\adapter\session\Entity',
333 'model' => 'app\models\Session',
334 'ini' => array(
335 'cookie_domain' => '.' . $host
336 )
337 )
338 ));
339 ```
340
341 ## Authentication ##
342
343 Even when you could easily build your own authentication library, using
344 [lithium's implementation] [lithium-authentication] is highly recommended. If
345 you wish to go this route, you'll need li3\_doctrine's Form adapter for
346 authentication, since it allows it to interact with Doctrine models.
347
348 The model you wish to use should extend from `BaseEntity` (you could still make
349 it work without extending from it if you implement the needed methods). We will
350 use the `User` model we created earlier.
351
352 Once you have your model, you need to configure `Auth`. Edit your
353 `app/config/bootstrap/session.php` and add the following to the end:
354
355 ```php
356 use lithium\security\Auth;
357
358 Auth::config(array(
359 'default' => array(
360 'adapter' => 'li3_doctrine2\extensions\adapter\security\auth\Form',
361 'model' => 'app\models\User',
362 'fields' => array('email', 'password')
363 )
364 ));
365 ```
366
367 Once this is done, you can use `Auth` as usual.
368
3a96489 @mariano Adding how to log queries to li3_perf in the documentation
authored
369 # Integrating libraries #
1bfb208 @mariano README updates
authored
370
371 In this section I'll cover some of the doctrine extension libraries out there,
3a96489 @mariano Adding how to log queries to li3_perf in the documentation
authored
372 and how to integrate them with li3_\doctrine2, and also how to let
373 li3\_doctrine2 work with other lithium extensions that may be usable.
1bfb208 @mariano README updates
authored
374
375 ## DoctrineExtensions ##
b7bce75 @mariano Adding README
authored
376
377 If there is one tool I would recommend you checkout for your Doctrine models,
e811e60 @mariano Fixing link reference in README
authored
378 that would be [DoctrineExtensions] [DoctrineExtensions]. It provides with a set
b7bce75 @mariano Adding README
authored
379 of behavioral extensions to the Doctrine core that will simplify your
380 development.
381
382 To use DoctrineExtensions, you should first add it as GIT submodule. To do so,
383 switch to the core directory holding your lithium application, and do:
384
385 ```bash
a6ef188 @mariano Recommending installation on main library folder
authored
386 $ git submodule add https://github.com/l3pp4rd/DoctrineExtensions.git libraries/_source/DoctrineExtensions
b7bce75 @mariano Adding README
authored
387 ```
388
389 Next you would use your connection configuration (in `app/config/connections.php`)
390 to configure Doctrine with your desired behaviors. For example, if you wish
391 to use Timestampable and Sluggable, you would first add the library in
392 `app/config/libraries.php`:
393
394 ```php
395 Libraries::add('Gedmo', array(
a6ef188 @mariano Recommending installation on main library folder
authored
396 'path' => LITHIUM_LIBRARY_PATH . '/_source/DoctrineExtensions/lib/Gedmo'
b7bce75 @mariano Adding README
authored
397 ));
398 ```
399
a165763 @mariano Making the creation of entity manager filterable
authored
400 And then you would filter the `createEntityManager` method in the `Doctrine`
401 datasource to add the behaviors. Edit your `app/config/connections.php` file
402 and add the following right below the connection definition:
b7bce75 @mariano Adding README
authored
403
404 ```php
a165763 @mariano Making the creation of entity manager filterable
authored
405 Connections::get('default')->applyFilter('createEntityManager',
406 function($self, $params, $chain) {
407 $params['eventManager']->addEventSubscriber(
408 new \Gedmo\Timestampable\TimestampableListener()
b7bce75 @mariano Adding README
authored
409 );
a165763 @mariano Making the creation of entity manager filterable
authored
410 $params['eventManager']->addEventSubscriber(
411 new \Gedmo\Sluggable\SluggableListener()
412 );
413 return $chain->next($self, $params, $chain);
b7bce75 @mariano Adding README
authored
414 }
a165763 @mariano Making the creation of entity manager filterable
authored
415 );
b7bce75 @mariano Adding README
authored
416 ```
417
3a96489 @mariano Adding how to log queries to li3_perf in the documentation
authored
418 ## Li3Perf ##
419
420 [li3_perf] [li3_perf] is a handy utility that you should use (only when the
421 development environment is activated, though) to keep track of bottlenecks,
422 and potential performance problems.
423
c7d9147 @mariano Fix docs
authored
424 One of the features it offers is the ability to show all the database queries
425 that were executed as part of a request. In order to use that functionality
426 with li3\_doctrine2, a little work has to be done. Fortunately, it's quite
427 easy.
3a96489 @mariano Adding how to log queries to li3_perf in the documentation
authored
428
429 Create a file named `Li3PerfSQLLogger.php` and place it in your
430 `app/libraries/_source` folder with the following contents:
431
432 ```php
433 <?php
434 namespace app\libraries\_source;
435
436 use Doctrine\DBAL\Logging\SQLLogger;
437 use li3_perf\extensions\util\Data;
438
c7d9147 @mariano Fix docs
authored
439 class Li3PerfSQLLogger implements SQLLogger {
3a96489 @mariano Adding how to log queries to li3_perf in the documentation
authored
440 public function startQuery($sql, array $params = null, array $types = null) {
441 Data::append('queries', array(compact('sql', 'params', 'types')));
442 }
443
444 public function stopQuery() {
445 }
446 }
447
448 ?>
449 ```
450
451 Now, we need to filter the `createEntityManager` method of the `Doctrine`
452 datasource. Edit your `app/config/connections.php` file and add the following
453 right below the connection definition:
454
455 ```php
456 Connections::get('default')->applyFilter('createEntityManager',
457 function($self, $params, $chain) {
458 if (\lithium\core\Libraries::get('li3_perf')) {
459 $params['configuration']->setSQLLogger(
460 new \app\libraries\_source\Li3PerfSQLLogger()
461 );
462 }
463 return $chain->next($self, $params, $chain);
464 }
465 );
466 ```
467
468 Notice how we are only using the logger we created if the li3\_perf library
469 is activated. If so, you should now see your queries on the performance
470 toolbar.
471
b7bce75 @mariano Adding README
authored
472 [lithium]: http://lithify.me
473 [doctrine2]: http://www.doctrine-project.org
474 [license]: http://www.opensource.org/licenses/bsd-license.php
475 [DoctrineExtensions]: https://github.com/l3pp4rd/DoctrineExtensions
b9bef23 @mariano README updates
authored
476 [doctrine-mapping-guide]: http://www.doctrine-project.org/docs/orm/2.1/en/reference/basic-mapping.html
889e90b @mariano Documentation updates
authored
477 [doctrine-querying-guide]: http://www.doctrine-project.org/docs/orm/2.1/en/reference/working-with-objects.html#querying
478 [doctrine-persisting-guide]: http://www.doctrine-project.org/docs/orm/2.1/en/reference/working-with-objects.html#persisting-entities
0db1df1 @mariano Documentation updates
authored
479 [lithium-authentication]: http://lithify.me/docs/manual/auth/simple-authentication.wiki
3a96489 @mariano Adding how to log queries to li3_perf in the documentation
authored
480 [li3_perf]: https://github.com/tmaiaroto/li3_perf
Something went wrong with that request. Please try again.