
We read:
Planet PHP
Planet MySQL
Exciting E-Commerce
E-Commerce Blog
Fischmarkt
fukami
Lars Jankowfsky
Themenblog
Thomas Bachem
Matt Asay on OpenSource
Joel on Software
Ibrahim Evsan
Hasematzel
Techcrunch
Indiskretion Ehrensache
Sichelputzer
Alexander Schwinn
Managing Tech
F-LOG-GE
trycatchfinally
In yesterday's article of our advent calendar, we explained the concepts underlying Doctrine 2. In today's article, we want to use that knowledge and create a simple Zend Framework (ZF) application that uses Doctrine 2 to persist its business objects.
While explaining how to integrate Doctrine 2 into Zend Framework, we will create a generic sandbox that can be used for future projects building up on these technologies.
Since this article is not about how to setup a ZF project, the following steps will require you to have a clean but working project with
the usual folder structure.
To use Doctrine 2 you will have to get a copy of its source code first. You can get one either from the project's website or by cloning the git repository. In my opinion, downloading the source package from the
website is a lot easier (you don't have to take care of all the project's git submodules etc.). So download and extract the archive into a
temporary directory. After that, move the folder Doctrine from the archive's root into the library of your new
ZF application. Now, your project structure should look like this:
The first thing that will occur to you if you look at the Doctrine 2 source code is that 100% of the code is
namespaced (for a (German) introduction to namespaces have a look at the article "PHP 5.3 Features in Real Life" from a colleague of mine). This is pretty nice for people who are not scared of new
language constructs but for many people that are using ZF it might look odd at first. I am sure that you will get familiar with the syntax
differences really fast, but ZF (1) does not - because it does support real namespacing yet (however this will change with version 2).
Therefore we have to do some additional work that enables us to autoload classes that reside in namespaces. Luckily, Doctrine 2 comes with
a neat set of helper classes bundled in the project Doctrine Common which
also includes a class loader that fulfills our needs. The class loader is called Doctrine\Common\ClassLoader and is really easy to use:
This code snippet creates and registers a new class loader that looks for classes in the namespace Doctrine. These classes should be placed in a folder called Doctrine which is part of the current include path. Every namespace separator will be transformed into a directory separator when looking for the classes, so make sure to keep your class-, namespace-, file- and folder-names in sync!
I recommend putting the initialization of the class loader into your application's bootstrap class because this way it can be used for cli scripts, too. As you might have seen, there are several packages inside the Doctrine folder that we placed in your library. The folders ORM, DBAL and Common contain the Doctrine 2 classes required by the framework. The fourth folder Symfony contains some classes borrowed from the Symfony2 framework. To load all these classes, we have to initialize multiple class loaders:
The initialization of the loaders responsible for Symfony2 and entity classes requires a second argument, that indicates the directory in which the classes of the namespaces can be found. If you do not provide this argument, the class loader just looks in the directories of your include path for folder names matching the given namespace.
The next thing we will do is creating an entity manager. To do so, we have to initialize a configuration object (of the type
Doctrine\ORM\Configuration) and pass it to the entity manager. Since we want to create a project that can be configured easily,
we separate the configuration data from the initialization code. Let's begin with the initialization code and add the required configuration
directives to our application.ini file later.
Instead of describing each single option here, I add some detailed comments in the initialization code:
From now on, you can access the entity manager by requesting it from the Zend_Registry. This should probably be done via a
dependency injection system, but this article will not cover how to implement dependency injection or even a dependency injection container.
To make this bootstrap code work, you will have to add the following directives to your application.ini:
Basically, this is all you have to do to integrate Doctrine 2 into your ZF application. It is fully functional with this
configuration, so let us take a snapshot of the project now and declare it as our sandbox for future ZF-Doctrine 2 projects.
\
Next, I want to show you how to create entity classes within your project and how to initialize a database scheme from these entities.
If you have read my yesterday's article, the following part will not look very new to you. I will create two entity classes: User and Group which have a n:m relationship called membership.
To write create tables in the database for these entities, we will use Doctrine's console tools which are really handy. Create a new
script named doctrine.php in your application's bin directory and copy the following code snippet into it.
This script sets up a Zend_Application first, bootstraps it and creates a normal Doctrine 2 console. You might want to have a
look at the original console script which is included in the Doctrine 2 archive we downloaded before. I added the ZF initialization
to be able to use the application's configuration here.
When you run the script now, the output should look like this:
All actions related to your database's schema have the prefix orm:schema-tool. Create your schema now by executing
$ php bin/doctrine.php orm:schema-tool:create
If you have no errors in your configuration, your database should have three new tables now: user, group and group_user.
Now you are ready to implement your application's logic. You can write code that queries, modifies and creates user and group objects and have all data persisted by Doctrine 2. To end this article, I just want to give you a feeling for how you might interact with Doctrine 2 in your business logic.
I hope this article helps you setting up the infrastructure for your next project and covers everything you have to know to begin using Doctrine 2. The sandbox we set up can be downloaded here. Make sure to include the current versions of ZF and Doctrine 2 after downloading it.
Object-relational mapping (ORM) frameworks have been around for several years now and for some people, ORM is already outdated by now. As we have seen with other technologies and concepts before, PHP is not exactly what we call an early adopter among the programming languages. Thus it took some time for ORM to grow up in the PHP context.
There have been some frameworks before Doctrine 2 that implement ORM (remember e.g. Propel) specific tasks but most of them lack the required maturity to be used in large projects. With Doctrine 2, PHP takes a huge step into the right direction – Doctrine 2 is fast, extensible and easy to use.
This article will take you on a tour through the main concepts of Doctrine 2 in the first part and then explain how to use it in a real world application in the second part. Since at the time of writing Zend Framework 1.11.xx (ZF) is very popular, we will integrate Doctrine 2 into a ZF project.
To understand Doctrine 2, we have to take a look at some relevant terms (or in this case objects), study their behavior and practice their usage. We start with some introductory phrases on ORM systems and then go on to the concepts underlying Doctrine 2: Entity Objects, the Entity Manager, Repositories and Proxies.
Since the beginning of Object-Orientation, people had to manage the persistence of their application's state resp.
their objects. In the context of Web Application Development, this usually involves a Database server which is being
consulted using a Query Language. One example for this pattern is a PHP application that uses some kind of SQL server
by sending SQL queries to it. Another one is an application using a CouchDB server by querying it via its REST API.
Due to the author's laziness, we will talk in terms of relational databases from now on. Keep in mind, that you can
accomplish almost everything mentioned here with NoSQL databases, too.
ORM relates value objects that exist in an application's business logic to database records.
Thus every object that should be persistent is saved in one row of a database table. The most common approach is to
map classes to tables and the classes' objects to rows in the these tables.
Besides writing objects to a database, ORM systems are also intended to ease the process of finding data stored in the
database. When talking in terms of ORM, finding data always means making the framework fetch one or many objects
that meet a certain criteria.
The objects that are being managed by an ORM system are called Entity Objects. Every entity object relates to one entry in a table. In Doctrine 2, the classes that represent entities do not have to fulfill special requirements like inheriting from a certain super class (as you might have seen in other database abstraction frameworks like Zend_Db). When creating a new entity class with Doctrine 2, all you have to do is to write down a regular PHP class with properties. Besides this, you have to provide some hints on how these attributes should be persisted. The information how entity attributes relate to columns in the DB is called Metadata. Metadata can be described in different ways: By default there are metadata drivers for descriptions in XML, YAML and PHP. The fourth and most popular driver is based on DocBlock annotations (since in PHP, annotations aren't a language feature as in Java (see Wikipedia), they are contained by the classes' and attributes' DocBlocks). We will use annotations to describe our entities metadata. To get an impression on how easy this is, take a look at the following example.
This example contains all it needs to tell Doctrine 2 about the new entity User. With this class, you can create,
find, delete and modify user objects and persist their state to the underlying database. But keep in mind: as long
as you don't need any persistence features, you can use your user objects just like any other objects!
The next two objects resp. object types we will describe are responsible for doing the ORM functionality: persisting and finding.
To use ORM functionality, the Entity Manager (Doctrine\ORM\EntityManager) is the main access point to Doctrine 2. The entity manager is
responsible – as you might have guessed – for managing entities and for building a facade for the whole framework.
To accomplish its tasks, the entity manager uses some helpers. The Unit of Work object for example collects entities
that should be written back to the database and is capable of doing this in batches. This way, database operation
can be executed with almost no overhead and therefore are really fast.
Another dependency of the entity manager is the Event Manager. To be as extensible as possible, Doctrine 2 comes with an event system that publishes all important state changes to the outside as events. You can register for such events and extend the life cycle of your entity objects at one single point.
The entity manager's API combines methods for managing entities (find, persist, contains, copy, detatch, merge,
remove and refresh), methods that control the use of transations (beginTransaction, commit, flush, rollback and
transactional) and some helper methods for creating custom queries and accessing some of the entity manager's dependencies.
The following example shows how to query an object from the entity manager, modify it and write the changes back into the database.
Creating a new persistent object is almost as easy as modifying it:
For finding entities, Repositories are used. Every entity class has its own repository which is responsible for finding entities of that type. By default, repositories have some handy methods for fetching entities that match certain criteria:
find: Finds an entity by its primary key / identifierfindAll: Finds all entities of the repository's entity typefindBy / findOneBy: Finds all resp. one entity that matches the passed criteria:findBy<attribute> / findOneBy<attribute>: Magic methods that ease the filtering by a single attribute:
To access a repository, all you have to do is ask the entity manager for one. If you have implemented your own
repository, it will be returned by Doctrine\ORM\EntityManager::getRepository(). Otherwise, Doctrine 2 will provide
a generic repository. The main reason to implement custom repository classes is to group custom queries for an entity
type to make them reusable. For custom query logic, there are several mechanisms you can use: You can either use
Doctrine's query builder that implements an API similar to Zend_Db_Select or queries written in the Doctrine Query
Language (DQL) or you can even execute plain SQL queries. With these options, it is also possible to migrate old
applications which use complex queries by just wrapping these queries into the methods of custom repositories.
When traversing a graph of entity objects (which is required when entities are having relations to other entities),
it would be very expensive (in the sense of “requiring many database queries”) to fetch every depending entity with
an additional query. Therefore Doctrine 2 uses the concept of Proxy objects that represent regular entity objects
which have not been populated with data from the database. Take a look at the following example where the entity
Group aggregates a list of User objects in its member property. When accessing the members list, Doctrine 2 provides a
collection of proxy objects instead of complete User objects. When an object of this collection is being asked for
one of its properties, Doctrine loads the object's data from the database. This way, the users' data is not loaded
until it is really needed.
This section describes some advanced concepts that are required when mapping entity classes that have relationships to
other entity classes. Possible relationship types are association and inheritance. Inheritance is the mechanism used for
representing subtypes in object-oriented programming languages. An example would be a class User that implements
methods every user of a software should have and a class Administrator inheriting from User that adds methods for
determining the administrator's access rights.
Association is a weaker relation type. It means that an entity object can be related to other entity objects of other types. In terms of relational databases, there are three types of association which differ in the number of entities an object is related to: 1:1, 1:n and n:m relationships. n and m are placeholders and mean multiple.
To put objects of an entity type into relation, you just have to mention this relation in the entity class' mapping
information. The simplest case is a unidirectional 1:1 relationship. In the following example we describe a User entity
which has its access information (user credentials) encapsulated into another entity class called UserCredential. Since
every user has at most one credential object and every credential object may only be associated to one user object,
this is a 1:1 relationship.
If the relationship should be bidirectional, include the OneToOne attribute in the other class, too, and add an
attribute which denotes the attribute of the other entity that mapps the related object:
This way, you can access the user object from the credentials object, too.
Most of the times, developers have to deal with relationships which include many objects on at least one side.
These relationships are called 1:n or n:m relationships. This means that either one or multiple entities are standing
in relationship with an arbitrary number of entities of another type. To accomplish this, you have to use the mapping
keywords OneToMany or ManyToMany when describing your entities. Besides that, the mapping works the exact same way as
with 1:1 relationships.
There are however some tricks you should know when dealing with collections of associated entity objects. Consider
the following relationship between the entity classes User and Group:
When a group has at least one member, the group object will have a collection of the type
Doctrine\Common\Collections\ArrayCollection set as its members property. This collection contains
all user objects (or proxy objects as we have seen before) and can be modified intuitively with the methods add and
removeElement. To honor object-orientation, you might want to introduce custom methods for these tasks. If you do so,
you get into trouble when the group object does not have any users associated. In this case, the collection will simply be
set to null. To avoid checks whether the collection has already be initialized, you should to this by yourself
in the entity class' constructor:
It is also important to notice that one entity has to update the other entity's state as well when a relationship between to objects is created or removed. Take care to do this only in one class to avoid endless recursion loops! This class is called the Owning Side of the relationship. When implementing a bidirectional relationship, the other class is called the Inverse Side. It is important to determine owning and inverse side and implement the the classes accordingly to avoid greater trouble during debugging.
There are some more features implemented by Doctrine 2 enabling developers to specify their entities' relationships including sorting, pre-fetching and indexing. These topics are not covered in this article but are explained very understandable in the Doctrine 2 documentation.
Subtyping can be implemented in different ways using Doctrine 2. The main difference between these implementations is how the inheritance is mapped to the database. The options are to have one table for every class (Class Table Inheritance), to have one table for all classes in a hierarchy (Single Table Inheritance) and to have a table for every specialized sub-class of a given super-class (Mapped Super Class).We will give a short overview on all three alternatives, you have to pick the right one yourself. This decision should be made based on how many common attributes there are in your sub-classes.
Introducing a mapped superclass is probably the easiest way for specifying inheritance but might lead to many duplicate columns in your database schema. The superclass of your entities is not being declared as an entity itself (and might also be declared abstract) but provides attributes and optionally methods that will be available in all subclasses. When creating the database schema, Doctrine 2 merges all attributes and relationships of the superclass into the definitions of the subclasses and processes them as regular entities.
After creating the database from this mapping information, your tables will look like this:
When having entities that are very similar besides some few attributes, you might want to store them together in one database table. This approach is called Single Table Inheritance. To distinguish between the different types, there is always a column marked as discriminator column and a discriminator map that tells Doctrine 2 which values in the discriminator indicate what entity types.
These definitions cause the existing of one single table called User with all the attributes declared inside the classes User and Administrator plus a column type – the discriminator column. When working with entities of these types, Doctrine will manage the type flag automatically for you.
The resulting database schema looks as illustrated by the following diagram:
Having each entity type stored in its own table is always good for keeping your schema extensible. When you have to create a new subtype, Doctrine 2 will just create a new table for this type and it can inherit the logic and common attributes of a superclass. The only overhead you have with this approach is that all tables that correspond to subtypes have to maintain a relationship to their supertype's table. Using class table inheritance, the example with the entities User and Administrator looks like this:
Besides the inheritance type, there is no difference to the example using single table inheritance. The outcome on the resulting database scheme is huge. Now you have to separate tables which store users and administrators. Every record in the table Administrator has a corresponding record in the User table.
This was the first part of this article. Stay tuned for part II which will be published tomorrow (on 6th of December 2011)! In the second part, we will integrate Doctrine 2 into a Zend Framework application and include a generic sandbox (ZF-)project with Doctrine 2!
Here is a short example how a test for jsTestDriver could look like
MathmaticsTest = TestCase("MathmaticsTest");
MathmaticsTest.prototype.testAdd = function() {
var mathmatics = new school.Mathmatics();
assertEquals(3, mathmatics.add(1,2));
}
MathmaticsTest.prototype.testSub = function() {
var mathmatics = new school.Mathmatics();
assertEquals(1, mathmatics.sub(4,3));
}
MathmaticsTest.prototype.testDiv = function() {
var mathmatics = new school.Mathmatics();
assertEquals(4, mathmatics.div(8,2));
}
MathmaticsTest.prototype.testMultiple = function() {
var mathmatics = new school.Mathmatics();
assertEquals(9, mathmatics.multiple(3,3));
}
An sich bin ich ja bekennender Fan der Playstation Portable (PSP). Zumindest wenn man sich die Anzahl der Spiele ansieht, die ich für die PSP besitze. Unsere beiden Mayflower Standorte sind schon länger mit der Wii ausgerüstet, doch an Weihnachten war es auch bei mir soweit: mich hat das Wii Fieber erwischt. Wer Techcrunch liest, der weiß, dass Amazon zur Weihnachtszeit 17 Wii pro Sekunde (!) verkaufen konnte.
Doch was ist eigentlich das Faszinierende an der Wii? Die Auflösung ist, verglichen mit einer PS3 oder XBox, ziemlich simpel. Neuartig jedoch ist, dass man nicht mit einem simplen Daddel-Controller ausgerüstet wird, sondern man den Controller und das begleitende Nunchuk entsprechend mit vollem Körpereinsatz bewegen muss, um das jeweilige Spiel zu steuern. An dieser Stelle sei gesagt, dass "Rayman Raving Rabbits" meiner Meinung nach ein unbedingtes Must Have ist. Wer schon immer mal auf einem Warzenschwein reiten wollte oder niedliche kleine Hasen erschlagen möchte, dem sei dieses Spiel ans Herz gelegt. :-) In der Grundausstattung ist neben einem Controller und einem Nunchuk (hier hätte man sich zumindest 2 Controller und 2 Nunchuks per default gewünscht) noch das Wii Sports Game dabei, bestehend aus Tennis, Bowling, Golf und Boxen.
So schaffte es Nintendo 2007, wieder ordentlich nach vorne zu kommen, wurden sie doch von Sony (Playstation) und Microsoft (XBox) ziemlich abgehängt. Wenn man innovativ sein möchte, lohnt es sich, auch mal Neues auszuprobieren, und nicht den Marktbegleitern einfach hinter her zu hecheln. Nintendo erschließt sich mit der Wii dabei neue Zielgruppen (insbesondere Familien oder Menschen, die aus dem Spielkonsolen-Alter "rausgewachsen" sind), die sonst nie mit einer Spielekonsole spielen würden - Hardcore-Gamer, die sich lupenreine Grafik und Action wünschen, werden sicherlich eher zur XBox oder PS3 greifen.
Ein ausführlicheres Porträt zur Innovationskraft von Nintendo mit der Wii gab es in einer der letzten Ausgaben der WirtschaftsWoche, leider nicht online verfügbar.
In diesem Sinne: thumbs up für eine tolle Innovation - vielleicht infiziert Sie auch das Wii-Fieber? Einstweilen wünschen wir Ihnen ein gutes Neues Jahr 2008!
Disclaimer: Nintendo of Europe ist einer unserer Kunden.



















