Since I am actively playing around with it, I wanted to share some snippets to use the Doctrine OrientDB ODM in your PHP applications.
Prelude
In the last few weeks I’ve started working, for fun and profit, to a personal project, nothing really exciting as of now.
The thing is, since I wanted to get back on some cool piece of software, I decided to go for OrientDB for the persistence and a mini-framework a-la Symfony2 as foundation for the PHP application – I actually considered NodeJS first, but I need a prototype in 2 months so…
Point being, I’d like to share with you my basic approach to the OrientDB ODM.
The container
Given I’ve been inspired to Symfony2, instantiating the main ODM classes happens in the DIC:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
|
As you see, you need:
- the
Manager
, which requires aMapper
and a connection to OrientDB through a binding class implementing theDoctrine\OrientDB\Binding\BindingInterface
- the
Mapper
, which requires a directory where it can write proxy classes (for lazy loading), and an annotation reader (this is not required, I’ll explain it later), plus a source directory to locate entities - the
HttpBinding
, used by theManager
, that does raw queries to the OrientDB server - the
Annotations\Reader
- a cache implementing the interface
Doctrine\Common\Cache\Cache
: in dev environments it is needed sinceApcCache
is the default one, and you would need to flush APC every time you change an annotation in your entities (we will probably change it and putArrayCache
by default, so that you will need to tweak the live environment, not the dev one)
Autoloading
The autoloading is straightforward, thanks to the PSR-0
; the
only thing that you should keep in mind is that you will need
to specify a separate autoloader for proxy classes, since they can
be generated wherever you want (ideally, in a temporary folder,
since they should be removed every time you deploy):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
You should set the autoloader for Doctrine\OrientDB\Proxy
accordingly to the argument documentProxyDirectory
of the
odm.mapper
service.
Entities
Following what we specified in the container.yml
,
entities should be located in
%base-dir%/src/PROJECT/Entity/
and follow the namespace
PROJECT\Entity
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
|
As you see, mapping an entity is pretty easy: the first annotation is at class level, to define which OrientDB classes are mapped by the entity, then for every property that you want to be persisted / hydrated, you define another annotation and public getters / setters; if you want the property to be public, you dont need getters / setters.
The property-level annotation has 3 parameters:
- type: defines the type of the property in OrientDB
(
boolean
,link
,linklist
,string
,integer
, etc ) - name: the name of the attribute in the OrientDB class
(you might have a PHP property called
$createdAt
and in OrientDB you call itcreated_at
) - notnull: defines whether the property can be
null
or not1
What about controllers?
You can access the ODM from within controllers of your application by just using the container:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
Repositories
At this point, after boostrapping the environment and creating your first entity, you might want to play with the repository in your controllers, to manipulate and retrieve collections:
1 2 3 4 |
|
then, with the repository, you can start retrieving objects:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
and it’s not over, since you can, of course, add custom repository classes.
Custom repositories must be located in the entity’s folder
and follow the naming convention EntitytheymapRepository
:
for our User
entity, we would need to create a UserRepository
class in %base-dir%/src/PROJECT/Entity/
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
so then you can call your new methods over repositories:
1 2 3 |
|
Can I haz raw queries?
Entities and repositories are good, but what about
adding some SQL+
2 to the mix?
That’s very easy, thanks to the query builder that’s packed with the ODM:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
When you manipulate the $query
object you are basically
creating an SQL query with an object-oriented fluent interface;
to eventually execute the query, just pass the object to
the Manager
:
1 2 3 4 5 6 |
|
Point being, how do you save data?
Since persistence is not already handled by the Manager
,
you will need to use raw queries for now:
1 2 3 4 5 6 7 8 9 10 |
|
From the trenches
We’ve been very active since a couple months, and we’ve actually been able to roll out some major bugfixes and improvements (more than 10 in the last few weeks):
- repositories filtering by multiple criterias
- custom repository classes
- added ability to map timestamps as DateTime objects
- unable to update attributes if they are a collection
- support for INSERTing collections
- proxy classes dont import signatures
findBy*
andfindOneBy*
“magic” methods- fetchplans in
find*
methods of repositories - following
SQL+
, addedREBUILD INDEX
command
I would not advise you to install one of the old tags, or even the last one, which brings the namespace changes for the incubation in the Doctrine organization, but to install it directly from master via composer:
1
|
|
as we are constantly doing bugfixes and so on (I would day you would get an update – at least – every week).
That is it, now start playing around!
- Be aware that if you are retrieving a property which is NULL in the DB and you don’t declare it as NULLable, an exception will be thrown (and there is an issue to improve the exception message https://github.com/doctrine/orientdb-odm/issues/152) ↩
- OrientDB’s QL is called SQL+, as it looks like SQL but has some major improvements, as it’s very developer-friendly ↩