Doctrine Contrexx 3.0
Contents
Content
Doctrine (see http://en.wikipedia.org/wiki/Doctrine_(PHP) ) is an Object Relational Mapper (ORM) for PHP.
This article describes the integration of Doctrine 2 in Contrexx.
Visualisation
Doctrine 2
A must for the understanding of Doctrine is the understanding of Namespaces (one of plenty tutorials).
The "Getting Started"-Tutorial gives an overview over the possibilities and concepts of Doctrine. This article is based on the terms and definitions used in the tutorials.
More detailed documentation resources are:
Extensions
Doctrine 2 is based on modules. We are using Gedmo/Loggable and Translatable. More information and documentations on [1] or with the Maintainer [2].
Folder structure in Contrexx
Entities / Repositories
Under model/entities/Cx/Model/ are the Entities and Repositories. After model/entities the path is equal to the used namespace.
model/entities/Cx/Model/ContentManager/Page.php also contains a class \Cx\Model\ContentManager\Page, model/entities/Cx/Model/ContentManager/Repository/PageRepository.php the corresponding repository.
Hint: to get repositories, you have to provide the whole path, example
$entityManager->getRepository('Cx\Model\ContentManager\Page');
, otherwise the entity won't be found.
Validating of entities
Example under model/entities/Cx/Model/ContentManager/Page.php
A class, which should use a validation, must inherit from \Cx\Model\Base\EntityBase:
class Page extends \Cx\Model\Base\EntityBase
After that you can assign an array with Zend_Validate instances (Documentation with an overview of all usable validator types) in the constructor to the variable $this->validators. There is a good example in the constructor of model/entities/Cx/Model/ContentManager/Page.php.
If you want to save a new or an existing entity via $entityManager->persist($entity), a ValidationException will be thrown.
try { $entityManager->persist($entity); $entityManager->flush(); } catch ( \Cx\Model\Base\ValidationException $ex ) { die("validation errrors: " . $ex->getMessage()); }
Entity manager
The entity manager can be retrieved by using Env::em() (a Shortcut for Env::get('em')).
Due to the testability, it is recommended to follow the instructions in the head of Env.class.php:
/** * A global environment repository. * * In old code, use this instead of global variables - allows central tracking * of dependencies. * Do *NOT* use this in new code, inject dependencies instead. * Example: * WRONG: * public function __construct() { * $this->entityManager = Env::get('em'); * } * RIGHT: * public function __construct($em) { * $this->entityManager = $em; * } * Reason: Global state is untestable and leads to inflexible code. */
Scheme files
Contrexx uses the YAML mapping for the scheme definitions. The mappings are located in model/yml.
Doctrine CLI / Helper scripts
In model are the Doctrine CLI (model/doctrine) and some helper scripts. All files are programmed for linux.
- generate_entities.sh allows to regenerate entities using the scheme files. Attention: Doctrine overwrites adjustments which you have done in the entity classes.
- dev_rebuilddb.sh updates the database after the scheme files have been modified. Attention: All data of the tables which are defined in the scheme files will probably be dropped!
Doctrine configuration
The configuration can be found in config/doctrine.php.
The line
//$config->setSqlLogger(new Doctrine\DBAL\Logging\EchoSQLLogger());
can be commented in to dump and debug the generated SQL.
Debugging
Along with the configuration change up above, Doctrine provides Doctrine\Common\Util\Debug. Dumps of Doctrine entities cannot be done with var_dump / print_r due to references to complex objects - the exception can take more than multiple minutes.
Doctrine\Common\Util\Debug will be used like that:
//define class local as DoctrineDebug use Doctrine\Common\Util\Debug as DoctrineDebug; //... DoctrineDebug::dump($entity);
SQL
With the following statement, the SQL queries of Doctrine can be printed out into the browser:
\Env::em()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger());
Testing
The tests are located in testing/tests/model.
It is highly recommended to write tests for each entity and repository: If something has been changed in the Model, it is used to check whether everything still works and whether you get the expected results. So you don't have to test manually the whole module.
There is a special test case testing/testCases/DoctrineTestCase.php, your test case should inherit from. This test case provides the entity manager and surrounds each test with an single transaction. So there will not be any change done to the testing database.
Example in: testing/tests/model/contentManager/PageRepositoryTest.php
Frequently errors
Fatal error: Uncaught exception 'ReflectionException' with message 'Class Page does not exist' in ...
The error is: no Namespace have been added to the parameter
$this->pageRepo = $this->em->getRepository('Page');
Correct:
$this->pageRepo = $this->em->getRepository('Cx\Model\ContentManager\Page');