
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!
public function delete($id) {
$sql = ‘DELETE FROM `‘ . static::getTableName() . ’`WHERE id=’ . $id;
$stmt = $this->getDb()->execute($sql);
return $stmt;
}
}Seit PHP die Objekt-Orientierung in genügendem Umfang unterstützt, gab es in Hinsicht auf die Code-Qualität von PHP-Applikationen große Fortschritte. Früher galten PHP-Entwickler als die Vandalen unter den Programmierern, da die Sprache - und dies ändert sich leider nur sehr langsam - sehr viele Möglichkeiten bot, undurchsichtigen und schlecht wartbaren Quellcode zu produzieren. Mit PHP 5 wurde ein großer Schritt in die richtige Richtung gemacht und heute ähnelt die Objekt-Orientierung von PHP der von Java sehr stark. Ende Juni 2011 wurde auf dieser Basis dann ein weiterer Schritt gewagt, der allerdings nicht von Java sondern von der aktuell immer stärker an Popularität gewinnenden Sprache Scala inspiriert wurde. Das neue Sprachfeature nennt sich Traits und ermöglicht Klassen-übergreifenden Code-Reuse ohne vertikale Vererbung. Was sich hier hochgestochen anhört, ist grundsätzlich ein relativ einfacher Mechanismus, der im Folgenden anhand eines simplen Beispiels erläutert wird.
During the development of an application, not all time is spent on writing code. A lot of time is spent on reading debug output, crawling through log files and firing up the debugger to figure out what the application does. While the debugger helps us to inspect details of a running application on a testing environment, logfiles are often the only indication of the origin of an error on a production system. In this blogpost I want to describe how to log SQL statements on an existing application without touching any existing line of code at all. We will use a new MySQLnd Extension developed at the Mayflower OpenSource Labs for that purpose.
As an example, I will use PHProjekt 6. The project is particularly suitable for demonstration purposes as it has a logging infrastructure for function calls, but does not log SQL statements.
Am vergangenen Wochenende (12.09./13.09.09) fand die dritte PHP-Unconference in Hamburg statt. Organisiert wurde die Unconference von der Hamburger PHP-User-Group im Geomatikum. An dieser Stelle möchte ich gleich dem Team danken, die Organisation war wirklich spitze, es fehlte an nichts.
Dies war meine erste Unconference und im Vorfeld war ich etwas skeptisch, denn es gab keine Liste mit Speakern und eingereichte Vorträge oder einen festen Zeitplan, lediglich auf der Webseite wurden Vorschläge und Interessen der Besucher gesammelt. Aus der Sammlung dieser Vorschläge wurde dann an beiden Tagen abgestimmt, welche Vorträge gehört werden wollen. Jedem Besucher standen dazu am Samstag und Sonntag jeweils drei Stimmen zur Verfügung, die mittels Aufkleber an die Vorträge vergeben werden konnten. An den Ergebnissen dieses Wahlverfahrens konnte man meiner Meinung nach auch erkennen, was die PHP-Community bewegt und vielleicht auch, in welche Richtung sich die Programmierung mit PHP in nächster Zeit entwickeln wird. Das schließe ich daraus, weil Vorträge wie „PHP Enterprise-Skalierbarkeit und Sicherheit“, „QA in Zukunft“, „Domain Driven Design“, „Test Driven Design“, „Scrum“, „Softwaremetriken“, „MVC Design Pattern“ und „Unit testing“ bestens besucht waren und die Diskussionen dazu oft über den Vortrag hinaus andauerten.
In denen von mir besuchten Vorträgen gefiel mir die Diskussionen zum Model View Controller Design Pattern mit Stefan Priebsch und den anwesenden Zuhörern am besten. Weit über den geplanten Zeitrahmen hinaus wurde besprochen, wie „Best Practises“ in der Umsetzung des Entwurfsmusters mit dem Zend Framework aussehen könnten. Aber auch in den anderen Vorträgen wurde eifrig diskutiert. Bei „PHP-Enterprise- Skalierbarkeit und Sicherheit“ wurde von Kris Köhntopp an Hand von vielen Beispielen gezeigt, wie überhaupt eine „Enterprise-Umgebung“ aussieht und welche Anforderungen dabei nicht nur an den Quellcode sondern auch an die einzelnen Softwareentwicklungsprozesse entstehen. Lars Jankowfsky und Johann-Peter Hartmann trugen mit ihren Erfahrungen zur Diskussion bei und belegten die Aussagen von Kris Köhntopp mit Beispielen.
Ein völliger Kontrast bildet der Vortrag „Rich Internet Applications mit Adobe Flex und Zend Framework“. Dabei stand nicht die Entwicklung mit PHP und dem Zend Framework in Mittelpunkt, sondern wurde gezeigt, wie mit PHP eine Schnittstelle zu Actionscript geschaffen werden kann und somit das Flex- Framework genutzt werden kann. Speaker Jörg Ohnheiser argumentierte den Einsatz von Flex mit den reichhaltigen GUI-Elementen die zur Verfügung stehen und der dadurch besseren Usabillity. Ich konnte nicht überzeugt werden und vertrete auch weiterhin den Standpunkt, dass auch mit Javascript- Toolkits, die solche GUI-Elemente enthalten, die Usabillity von Webanwendungen verbessert werden kann- unabhängig von einem einem Browser-Plugin (wie dies der Fall ist bei Flex- Anwendungen). Einzig bei Video- und Audio-Inhalten macht der Einsatz von Flex für mich Sinn.
Nike+ is a feature for the iPod nano which allows to measure time, distance and speed of runnings with a small sensor in running shoes that sends data to a transmitter on the iPod. Those data are sent to a users Nike+ account by iTunes whenever the iPod is synchronized. On the Nike+ website there is a report of runnings, the average speed, total kilometers run etc. The users can also compete with each other in virtual competitions and define goals to run more often, faster or a longer distance. The Nike+ website displays the data graphically with Adobe Flash.
There is no official API that allows you to use the raw data. Nevertheless the data are sent to the Flash via XML so there is a chance to use them. For PHP Rasmus Lerdorf himself has implemented a class to access these data. The class allows to authenticate a user and fetch the running data of a user in a XML-Format. This class can be found under Nike+ PHP API. To use that class you just have to create an object and pass the user credentials and optional caching parameters:
include("nikePlus.php");
$mynike = new NikePlus("user@domain.de", "password");
After the instantiation the object contains a SimpleXML object with all running information of that user that can be processed by any PHP application. The variables $data, $run, $challenges and $goals hold the information of the user account, runnings, ongoing challenges with other users and the personal goals of a user.
A partial output of the $data variable is shown below and contains among other things the total statistics of a user and the last recent run. The other data are represented in a similar way.
object(SimpleXMLElement)#3 (5) {
["userTotals"]=>
object(SimpleXMLElement)#7 (4) {
["totalDistance"]=>
string(8) "106.5635"
["totalDuration"]=>
string(8) "40500702"
["totalRuns"]=>
string(2) "21"
["totalCalories"]=>
string(4) "5195"
}
["mostRecentRun"]=>
object(SimpleXMLElement)#9 (4) {
["@attributes"]=>
array(1) {
["id"]=>
string(10) "1155526254"
}
["startTime"]=>
string(25) "2008-04-20T10:40:54+02:00"
["distance"]=>
string(6) "6.6107"
["duration"]=>
string(7) "2303090"
}
}
The Nike+ data can be used to display them on a website or to use them for mash up applications. For example there is already a word press plugin to display the data on a Blog System. Also there is another community called Runner+ which displays the data in a way similar to the Nike website.
After successfully passing the MySQL 5.0 Developer exams earlier this year the next step was preparing for the Zend Certified Engineer.
For preparation I first took php|architect's Zend PHP 5 Certification Study Guide from the bookshelf and started reading. The book gives a good overview of the topics covered in the exam and I even learned a few things while reading that I did not knew of before. Unfortunately it contains too many errors and mistakes in the printed examples and there is no errata on the internet.
After reading through the book I first did not really knew how to proceed in preparing for the exam. I did not have the feeling of being prepared to pass an exam, although I would think myself of a quite good and experienced PHP programmer. A really good thing is that everyone at Mayflower has the possibility to take some text exams at Vulcan, the Zend PHP 5 Certification Simulator (also from php|architect). I passed the first test exam but afterwards I knew which topics needed more attention and some serious learning. So back to the book and the PHP manual for some days reading. After passing another test exam I felt prepared enough for the real one.
Some days ago I finally went to the local testing center with some of my colleagues and all four of us passed the real exam.
Sounds hard? Well, PHP5 has been there several years and has been proven rock-solid. I appreciate the go-php5 project and want to support this with the following announcement:
With the beginning of issue 1.08 (coming to the newsstands in November 2007), PHP Magazin won't accept any articles or source codes that cover PHP4 topics or PHP4 sourcecode. Sourcecode delivery must cover PHP 5.2 or greater.



















