Doctrine Project http://www.doctrine-project.org/ Persistence Libraries for PHP en-us Thu, 18 Dec 2014 00:00:00 +0000 http://www.doctrine-project.org/2014/12/18/annotations-122.html http://www.doctrine-project.org/2014/12/18/annotations-122.html <![CDATA[Annotations 1.2.2 released]]>

Annotations 1.2.2 released

We are happy to announce the immediate availability of doctrine/annotations 1.2.2.

The release includes following fixes:

You can install the Annotations library using Composer and the following composer.json contents:

{
    "require": {
        "doctrine/annotations": "1.2.2"
    }
}
]]>
Thu, 18 Dec 2014 00:00:00 +0000
http://www.doctrine-project.org/2014/12/16/orm-247.html http://www.doctrine-project.org/2014/12/16/orm-247.html <![CDATA[ORM 2.4.7 released]]>

ORM 2.4.7 released

We are happy to announce the immediate availability of Doctrine ORM 2.4.7.

The release includes a fix for null values in column mapping options support: DDC-3425 We also fixed various Paginator tool issues:

  • allowing DQL queries that have HIDDEN selected fields appearing both in the SELECT and the ORDER BY clauses: DDC-3434
  • allowing DQL queries that have SELECT clauses containing parameters: DDC-3336

You can find all the changes on JIRA:

You can install the ORM using Composer and the following composer.json contents:

{
    "require": {
        "doctrine/orm": "2.4.7"
    }
}

Please report any issues you may have with the update on the mailing list or on Jira.

]]>
Tue, 16 Dec 2014 00:00:00 +0000
http://www.doctrine-project.org/2014/12/04/doctrine_dbal_2_5_release.html http://www.doctrine-project.org/2014/12/04/doctrine_dbal_2_5_release.html <![CDATA[Doctrine DBAL 2.5 Release]]>

Doctrine DBAL 2.5 Release

We are happy to announce the immediate availability of Doctrine DBAL 2.5.0 Stable. This release is a landmark in making DBAL more consistent and stable than it ever was.

Starting with 2.5 DBAL will have a new release-master, Steve Müller. Steve has been working on DBAL for the last two years and contributed many of the big features that make up this fantastic release. He will replace Benjamin Eberlei who was the release master since version 2.0.

You can install DBAL through Composer:

{
    "require": {
        "doctrine/dbal": "2.5.0"
    }
}

This version is mostly backwards compatible with only some minor breaks, when using PDO IBM, creating a custom platform or using non-default DateTime formats. You can see the breaks in the UPGRADE.md file. DBAL 2.5 is also compatible with ORM 2.4, there is no need to wait for ORM 2.5 to be released.

The following list contains the major new features of DBAL:

  • Support for SAP Sybase SQL Anywhere versions 10, 11, 12 and 16 (DBAL-475)
  • Support for auto-commit=NO on all drivers and platforms. (DBAL-81)
  • Refactor exceptions to use common error-codes and exception classes that derive from Doctrine\DBAL\DBALException. (DBAL-407)
  • Add support to retry connections with Doctrine\DBAL\Connection#ping() method. (DBAL-275)
  • Add INSERT support to QueryBuilder (DBAL-320)
  • Add Binary type for VARBINARY support (DBAL-714)
  • Add charset and SSL connection support to PostgreSQL (DBAL-567, DBAL-702)
  • Add options support for Myqli (DBAL-643)
  • Add support for using database uris with the url parameter in DriverManager::getConnection() which supports several forms used by PaaS providers out of the box (DBAL-1050).
  • Auto detection of platform to use based on database (DBAL-757)
  • Improved SQL Server LIMIT emulation support. (Multiple tickets)
  • Improvements to HHVM Support (no full support yet)

See all the changes for the 2.5.0 Release on Jira, an amazing total of 316 issues:

If you find any problems or backwards compatbililty breaks with this release please report them on JIRA or open up Pull Requests on Github.

]]>
Thu, 04 Dec 2014 00:00:00 +0000
http://www.doctrine-project.org/2014/09/15/dbal-235.html http://www.doctrine-project.org/2014/09/15/dbal-235.html <![CDATA[DBAL 2.3.5 released]]>

DBAL 2.3.5 released

We are happy to announce the immediate availability of Doctrine DBAL 2.3.5, which fixes a minor issue introduced in 2.3.4 where null parameter values passed to one of the connection execution methods led to an error.

You can find all the changes on JIRA:

You can install the DBAL using Composer and the following composer.json contents:

{
    "require": {
        "doctrine/dbal": "2.3.5"
    }
}

Please report any issues you may have with the update on the mailing list or on Jira.

]]>
Mon, 15 Sep 2014 00:00:00 +0000
http://www.doctrine-project.org/2014/09/12/dbal-250rc2.html http://www.doctrine-project.org/2014/09/12/dbal-250rc2.html <![CDATA[Doctrine DBAL 2.5 RC2]]>

Doctrine DBAL 2.5 RC2

We are happy to announce the immediate availability of Doctrine DBAL 2.5 RC2, which fixes over 30 bugs including SQL Server LIMIT/OFFSET issues, several identifiers quotation issues, schema introspection related issues and many more. This release candidate also introduces some nice new features and improvements since Doctrine DBAL 2.5 BETA3:

  • Support for connection flags in the mysqli driver
  • Support for Spatial Indexes in MySQL
  • Support date arithmetic interval methods for seconds, minutes, weeks, quarters and years
  • Support for Partial Indexes in PostgreSQL and SQLite
  • Doctrine\DBAL\Connections\MasterSlaveConnection can now be closed via close()
  • Ability to retrieve parameter types from the query builder
  • Make table alias in query builder optional for simple queries

We hope this will be the last release candidate before final release and you should expect to see the finished DBAL 2.5 very soon.

For details about all the new features in DBAL 2.5, see the previous release blog post and the Jira Release.

You can install the Release Candidate through Composer with the following version constraint:

{
    "require": {
        "doctrine/dbal": "2.5.0@RC"
    }
}

DBAL 2.5 is backwards compatible to 2.4 and earlier in everything except for small details (See UPGRADE.md). You can even test Doctrine DBAL 2.5 with a stable ORM 2.4 version.

If you find any problems with this beta, please report a bug on Jira.

]]>
Fri, 12 Sep 2014 00:00:00 +0000
http://www.doctrine-project.org/2014/09/11/orm-244.html http://www.doctrine-project.org/2014/09/11/orm-244.html <![CDATA[ORM 2.4.4 released]]>

ORM 2.4.4 released

We are happy to announce the immediate availability of Doctrine ORM 2.4.4, which fixes a minor regression introduced by DDC-2996.

You can find all the changes on JIRA:

You can install the ORM using Composer and the following composer.json contents:

{
    "require": {
        "doctrine/orm": "2.4.4"
    }
}

Please report any issues you may have with the update on the mailing list or on Jira.

]]>
Thu, 11 Sep 2014 00:00:00 +0000
http://www.doctrine-project.org/2014/09/11/instantiator-1-0-0.html http://www.doctrine-project.org/2014/09/11/instantiator-1-0-0.html <![CDATA[Doctrine Instantiator 1.0.0 released]]>

Doctrine Instantiator 1.0.0 released

We released Doctrine Instantiator 1.0.0 several weeks ago.

This project has been migrated from ocramius/instantiator into the doctrine organization to have better maintenance, support as well as handling of security related issues, which is a priority for us.

The migration has been done because all doctrine ORM and ODM projects were affected by a quite big backwards-incompatible change in PHP 5.4.29 and PHP 5.5.13, which was partially solved in PHP 5.6.0-RC3. The main tracking bug for this problem is DDC-3120.

Doctrine Instantiator provides a simple API to build objects without directly relying on the serialization hack that has been explicitly used by all of our data mappers for quite some time.

Installation

You can install Doctrine Instantiator using Composer and the following composer.json contents:

{
    "require": {
        "doctrine/instantiator": "1.0.*"
    }
}
]]>
Thu, 11 Sep 2014 00:00:00 +0000
http://www.doctrine-project.org/2014/02/21/security_in_doctrine.html http://www.doctrine-project.org/2014/02/21/security_in_doctrine.html <![CDATA[Security in Doctrine]]>

Security in Doctrine

When using Doctrine in a project it is always a security critical component because it talks directly to your database. As such security is very important to us. In security however, context is important and providing you with query capabilities we have to expose you to the risk of SQL injections.

Doctrine cannot prevent you from building SQL injections into your applications and so can no other DBAL, because it would require hiding SQL completely. But hiding SQL completly is not wanted, because it is such a powerful language.

Therefore it is still your responsibility to make sure that you are using Doctrine correctly when working with SQL.

But how would you know how to do so? Until now we had some small bits about security here and there in the documentation, mostly in the chapters about Query objects. We came to the conclusion that this is not enough.

That conclusion sinked in with a security issue we became aware of last month, where one Doctrine user reported that one of the core Doctrine\DBAL\Connection APIs is supposedly vulnerable to SQL injection. When you use $connection->insert($tableName, $values), then both the table name and the keys (columns) of the $values array are not escaped, because we assume they are never user input.

We evaluated this issue together with Padraic Brady (a known PHP security researcher) and came to the conclusion that this is not a security issue for us. Why? Because we don’t think this part of the API can be secured and trying will make our users feel safe, when they are not. Using the DBAL APIs directly always posed a much higher risk than using just the ORM.

You might think we are nuts by just claiming a non issue, but consider the assumptions we make about tables and columns and our reasoning:

  • Quoting identifiers is bad, because it changes them from case-insensitive to case-sensitive. Even more weird, Oracle unquoted identifiers are uppercased, PostgreSQL unquoted identifires are lowercased. MySQL casing is based on a config option. Doctrine 1.* had various unfixable bugs because of identifier quoting, which is why we decided that Doctrine will not use automatic identifier quoting.
  • The APIs of Connection#insert(), Connection#update() and Connection#delete() therfore accept both quoted and unquoted table/column identifiers, because quoting is the users choice.
  • A mechanism to detect SQL injection in strings that can be either quoted or unquoted is impossible to write completly secure. There are too many edge cases to consider and there is a realistic chance to miss one of them.
  • If you provide an API that is just secure in 99.999% of all cases, then you should not claim it is secure at all.

At this point you can still think we are wrong releasing insecure software, however let me ask back: Isn’t PHP shipping insecure software by providing PDO? SQL injection is possible by using PDO wrong. I can enumerate lots of libraries where security is the developers responsibility: Template engines, authentication libraries and so on.

A proper secured system requires knowledge about the context. That is why any kind of database abstraction layers can never fully protect you from SQL injection, because it does not know the context you are using it in.

To avoid secret knowledge about our security assumptions we are now starting to be completly explicit about these issues. Both DBAL and ORM now contain a SECURITY.md file, which contains basic information about security and links to much more detailed documentation chapters on Doctrine security.

We have made an effort to list all the functions and operations that are safe from SQL injection. There are not very many of them in the DBAL, because it is such a low level library. The ORM however is pretty secure, except when concatenating user input into DQL and SQL queries.

Read all the information about Security in Doctrine in the documentation.

]]>
Fri, 21 Feb 2014 00:00:00 +0000
http://www.doctrine-project.org/2014/02/21/doctrine_2_5_beta3.html http://www.doctrine-project.org/2014/02/21/doctrine_2_5_beta3.html <![CDATA[Doctrine DBAL 2.5 BETA3]]>

Doctrine DBAL 2.5 BETA3

We have released the BETA3 of DBAL 2.5 after some more work on the many new features. For early testers, we have refactored the Exception support again and removed the constants in favour of a nicely designed Exception hierachy. Many other issues were fixed and we hope this will be the last beta release before a release candidate in early March and a final release in March as well.

For details about all the new features in DBAL 2.5, see the previous release blog post and the Jira Release.

You can install the BETA through Composer with the following version constraint::

{
    "require": {
        "doctrine/dbal": "2.5.0@beta"
    }
}

DBAL 2.5 is backwards compatible to 2.4 and earlier in everything except small details (See UPGRADE.md). You can even test Doctrine DBAL 2.5 with a stable DBAL 2.4 version.

If you find any problems with this beta, please report a bug on Jira.

]]>
Fri, 21 Feb 2014 00:00:00 +0000
http://www.doctrine-project.org/2014/02/08/orm-235-234.html http://www.doctrine-project.org/2014/02/08/orm-235-234.html <![CDATA[ORM 2.4.2 and 2.3.5 released]]>

ORM 2.4.2 and 2.3.5 released

Published: 08.02.2014

We are happy to announce the immediate availability of Doctrine ORM 2.3.5 and 2.4.2. Both versions fix 17 and 12 bugs respectively.

You can find all the changes on JIRA:

You can install the ORM using Composer and the following composer.json contents:

{
    "require": {
        "doctrine/orm": "2.4.2"
    }
}
{
    "require": {
        "doctrine/orm": "2.3.5"
    }
}

Please report any issues you may have with the update on the mailing list or on Jira.

]]>
Sat, 08 Feb 2014 00:00:00 +0000
http://www.doctrine-project.org/2014/01/01/dbal-242-252beta1.html http://www.doctrine-project.org/2014/01/01/dbal-242-252beta1.html <![CDATA[DBAL 2.4.2 and 2.5.0 BETA1 released]]>

DBAL 2.4.2 and 2.5.0 BETA1 released

Published: 01.01.2014

We are happy to announce the immediate availability of Doctrine DBAL 2.4.2 and 2.5.0 BETA1.

The new stable version 2.4.2 had 20 bugs fixed. You can install this version using Composer and the following composer.json contents:

{
    "require": {
        "doctrine/dbal": "2.4.2"
    }
}

You can see all the changes on Jira:

In the first 10 month of 2013 we watched the number of open issues cross 100 and peak at 250 in mid November, unable to do much about it due to time constraints. During the last two months however we have worked hard to lower the number of open pull-requests on DBAL from 50 to only 7 and push the number of open issues on DBAL+ORM down to 188 from 250. This has been a tremendous effort and it would not have been possible without our two new core team members deeky666 and kimhemsoe.

With the number of open bugs at 22 and open pull requests at 7 I am excited to say that DBAL 2.5 will be the most stable and complete version so far. It is mostly backwards compatible with only some minor changes necessary, when using PDO IBM, creating a custom platform or using non-default DateTime formats. You can see the breaks in the UPGRADE.md file.

There is also a nice list of new features:

  • Support for SAP Sybase SQL Anywhere versions 10, 11, 12 and 16 (DBAL-475)
  • Support for auto-commit=NO on all drivers and platforms. (DBAL-81)
  • Refactor exceptions to use common error-codes and exception classes that derive from Doctrine\DBAL\DBALException. (DBAL-407)
  • Add support to retry connections with Doctrine\DBAL\Connection#ping() method. (DBAL-275)
  • Add INSERT support to QueryBuilder (DBAL-320)
  • Add Binary type for VARBINARY support (DBAL-714)
  • Add charset and SSL connection support to PostgreSQL (DBAL-567, DBAL-702)
  • Add options support for Myqli (DBAL-643)

See all the changes for the 2.5.0 BETA1 on Jira:

You can install the BETA using Composer and the following composer.json contents:

{
    "require": {
        "doctrine/dbal": "2.5.0-BETA1"
    }
}
]]>
Wed, 01 Jan 2014 00:00:00 +0000
http://www.doctrine-project.org/2013/12/23/our-hhvm-roadmap.html http://www.doctrine-project.org/2013/12/23/our-hhvm-roadmap.html <![CDATA[Our HHVM Roadmap]]>

Our HHVM Roadmap

Facebook has been pushing HHVM alot lately , helping open source projects to get their test-suite running 100%. For Doctrine HHVM is particularly interesting, because of the performance gains that the complex PHP algorithms inside ORM would probably get. From my current feeling Doctrine will be the PHP open-source project getting the most gain from running on HHVM. However with the tests not yet passing on the ORM, we can only imagine how big that performance improvement will be.

One roadblock for us to investigate HHVM in more detail was missing CI support. But then Travis CI announced support for HHVM last week. With automated testing support available we think it is time to announce our official HHVM roadmap.

One of our goals for 2014 is running DBAL and ORM on HHVM with 100% of the testsuites passing. Every Doctrine subproject targeting to support HHVM will start running the tests against HHVM with allow_failure enabled on Travis CI. Whenever a Doctrine subproject passes all its tests on HHVM, we will remove the allow_failure and the project will be officially supporting HHVM from that version on.

So far we have been working on the Common projects to run on HHVM for several months now and Guilherme and Alexander are contributing to HHVM itself to get some missing APIs working. We are happy to announce that the following Common projects currently have full HHVM support from us:

Guilherme is working on getting Annotations and Cache working and the Common mainproject will be evaluated shortly after all the common projects succeed. DBAL and ORM will be much more work, but we are very confident to achieve this goal.

If you want to help us with this goal, you can check the current Travis failure reports of the projects and come up with ideas how to fix them in the Doctrine code or with bug reports for HHVM. We are glad to discuss these issues on Freenode IRC in channel “#doctrine-dev”.

With this announcement we hope that other PHP projects, frameworks and libraries will follow to make HHVM an official build target in the future.

]]>
Mon, 23 Dec 2013 00:00:00 +0000
http://www.doctrine-project.org/2013/11/12/doctrine-2-4-1.html http://www.doctrine-project.org/2013/11/12/doctrine-2-4-1.html <![CDATA[Doctrine 2.4.1 released]]>

Doctrine 2.4.1 released

Today we released Doctrine DBAL 2.4.1 and ORM 2.4.1 versions. It includes an important fix for a regression with array hydration. In total 6 tickets have been closed in both releases.

See all the changes:

Installation

You can install Doctrine using Composer and the following composer.json contents:

{
    "require": {
        "doctrine/common": "2.4.*",
        "doctrine/dbal": "2.4.1",
        "doctrine/orm": "2.4.1"
    }
}
]]>
Tue, 12 Nov 2013 00:00:00 +0000
http://www.doctrine-project.org/2013/09/25/phpcr-odm-qbv2.html http://www.doctrine-project.org/2013/09/25/phpcr-odm-qbv2.html <![CDATA[PHPCR ODM QueryBuilder v2]]>

PHPCR ODM QueryBuilder v2

managed to merge the new query builder.

I developed the original query builder about 9 months ago - it was one of my first contributions to the PHPCR-ODM doctrine project. It was heavily based on the ORM query builder and the consensus being that we should make the ODM as intuitive as possible for existing ORM users.

Abstracting PHPCR to fit the existing interface worked up until a point, we could implement the basic functionality of the ORM Query Builder exactly, things started to come undone when we looked at implementing joins.

I had added the joins in the API but didn’t get around to implementing them, the methods just threw “not implemented” exceptions. Later, when we wanted to implement them, it wasn’t so simple. Infact, upon closer inspection, many of the things available in the PHPCR API’s Query Object Model interface were not covered by the model of the query builder we had chosen, in short, it was not fit for purpose. I expounded this on the following wiki page:

As detailed in the above linked page, it seemed to me that either we implemented a 2 part factory heavy query builder or a fluent node based query builder. The node based design won. However, at the time I never imagined it would take so long to write! So nearly 2 months later here we are.

Some features of the new query builder

  • Can fully express the PHPCR QOM (Query Object Model).
  • Features a fluent interface.
  • Strict validation and helpful exception messages.
  • Less verbose than the PHPCR QOM model.

Lets compare a PHPCR QOM query with its new query builder counterpart:

The following two examples are equivalent and both select a blog posts with node name “My Post Title” having the ODM class “BlogPost”. We order the result set first by publishing date and then by title.

Using the PHPCR QOM:

<?php
$q = $qom->createQuery(
    // SourceInterface (from)
    $qom->selector('nt:unstructured', 'p')
    $qom->andConstraint(
        $qom->comparison(
            $qom->propertyValue('p', 'phpcr:class'),
            $qom->bindVariableValue('phpcr_class'),
            QueryObjectModelInterface::JCR_OPERATOR_EQUAL_TO
        ),
        $qom->comparison(
            $qom->nodeLocalName('p'),
            $qom->bindVariableValue('post_title'),
            QueryObjectModelInterface::JCR_OPERATOR_EQUAL_TO
        ),
        array(
            $qom->ascending($qom->propertyValue('published_on', 'p'))
            $qom->ascending($qom->propertyValue('title', 'p'))
        )
    )
);
$q->bindValue('phpcr_class', 'Blog\Post');
$q->bindValue('post_title', 'My Post Title');
$res = $q->execute();

Using the new PHPCR-ODM query builder:

<?php
$q = $documentManager->createQueryBuilder()
    ->fromDocument('Blog\Post', 'p')
    ->where()
        ->eq()->field('p.title')->parameter('post_title')->end()
    ->end()
    ->orderBy()
        ->asc()->field('p.published_on')->end()
        ->asc()->field('p.title')->end()
    ->end()
    ->setParameter('post_title', 'My Post Title')
    ->getQuery();
$res = $q->execute();

Whilst the two examples above are equivalent it should be noted that we are being slightly unfair to the PHPCR QOM as we are forced to add the phpcr:class constraint, which is a PHPCR-ODMism. Despite this, the new API is clearly less verbose and, I hope, more intelligible.

The API allows chaining together operands:

<?php
$qb = $documentManager->createQueryBuilder();
$qb
    ->from()
        ->document('Blog\Post', 'p')
    ->end()
    ->where()
        ->andX()
            ->orX()
                ->eq()->upperCase()->field('p.username')->end()->literal('DANTLEECH')->end()
                ->eq()->field('c.initials')->literal('dtl')->end()
            ->end()
            ->lte()->field('p.published_on')->literal('2013-09-14')->end()
        ->end()
    ->end();

The API also allows you to break the query into multiple statements:

<?php
$qb->from()->document('Blog\Post', 'p');
$qb->where()->eq()->field('p.title')->literal('Foobar');
$qb->orderBy()->asc()->field('p.title');

And to add extra criteria to an existing query builder instance (useful if the query builder is instantiated and initialized by a vendor library):

<?php
class MyExtension
{
    public function modifyQuery(QueryBuilder $qb)
    {
        $qb->andWhere()->field('f.site_id')->literal(1);
    }
}

As a bonus, the nature of the API also allows us to easily add multiple constraints to andX and orX operator nodes, something not easily done with the native PHPCR builder:

<?php
$qb->fromDocument('Blog\Post', 'p');

// we can add one or many constraints to an "andX" node...
$qb->where()->andX()
    ->fieldIsset('p.username')
    ->gt()->field('p.rank')->literal(50)->end()
    ->eq()->fueld('p.title')->literal('This is a title');

The documentation is now online and is made up of both a guide and a reference:

]]>
Wed, 25 Sep 2013 00:00:00 +0000
http://www.doctrine-project.org/2013/09/11/doctrine-2-4-released.html http://www.doctrine-project.org/2013/09/11/doctrine-2-4-released.html <![CDATA[Doctrine 2.4 released]]>

Doctrine 2.4 released

We are happy to announce the availability of Doctrine Common, DBAL and ORM versions 2.4. This took us much longer than planned and we are very sorry for all the delay that was mostly caused by contributers private and work lifes. For the next versions we will also try to keep the scope smaller, you will see that version 2.4 contains lots of small new features.

Starting with version 2.4 Doctrine will not be available over PEAR anymore. The maintenance of this deployment channel is too complicated, compared to the small number of people using it. We focus on shipping Doctrine with Composer , which is a superior packaging tool in our opinion. We will continue to make Doctrine available as standalone download through the Github releases pages.

Follow the links in the list to find the changelogs of the three new releases:

Backwards Incompatible Changes

There have been some BC breaks in the 2.4 releases, which are listed here:

  • DoctrineDBALSchemaConstraint API change
  • Compatibility Bugfix in PersistentCollection#matching()
  • Composer is now the default autoloader
  • OnFlush and PostFlush event always called
  • DQL: Parenthesis are now considered in arithmetic expression

You can read up in detail on BC breaks on the DBAL and ORM UPGRADE docs.

Installation

You can install Doctrine using Composer and the following composer.json contents:

{
    "require": {
        "doctrine/common": "2.4.*",
        "doctrine/dbal": "2.4.*",
        "doctrine/orm": "2.4.*"
    }
}

New Features

This release contains large amount of new features and improvements. Compared to the previous minor release not so many big-bang features, but many small improvements. The most important changes are listed here with small examples or links to their documentation.

  • ALTER TABLE support for SQLite (by hason) by creating new tables, moving all the data and then renaming.
  • Using EXTRA_LAZY fetch mode now also queries for single entities on collections with indexBy when using $collection->get() or accessing the collection via array access.
  • Added two new modes to proxy generation for development environemnts, first using eval and second by checking if the proxy file not exists.
  • Pass Event Arguments to entities lifecycle methods, allowing access to EntityManager.
  • Allow to order by associations when using EntityRepository#findBy().
  • Support for new NEW() operator in DQL which can be wrapped around the full SELECT-clause parts and instantiates an object by passing the parameters to the constructor. See the documentation for more details.
  • Support for @EntityListener annotation and XML/YML configuration, which allows adding listener services on a per entity level (not global). See the documentation for details.
  • Improved the ResultSetMapping to generate the SELECT clause for an SQL statement, thereby improving the usability of native queries alot. See the documentation for more details.
  • Introduced a factory for repositories that can be overwritten in the Doctrine\ORM\Configuration.
  • Added an interface for EntityManager called Doctrine\ORM\EntityManagerInterface and a decorator base class Doctrine\ORM\Decorator\EntityManagerDecorator.
  • Support for proxy objects for entities with public properties.
  • Add support for composite primary keys in DQL IDENTITY() function. See the documentation for more details.
  • Introduced ANSI SQL Quoting Strategy that does not attempt to quote and modify columns during SQL generation.
  • Joins between arbitrary entities are now possible in DQL by using the syntax FROM Foo f JOIN Bar b WITH f.id = b.id.

Documentation

With 2.4 we merged the documentation into the repositories itself. We have seen a much increased amount of Pull Requests since then and also improved the documentation ourselves quite alot for 2.4.

Besides fixes and additions of all the new features, we tried to improve the style of the documentation. Many of the chapters have been refactored completly and hopefully address many of the valid concers of our users.

]]>
Wed, 11 Sep 2013 00:00:00 +0000
http://www.doctrine-project.org/2013/05/11/doctrine-2-4-beta2.html http://www.doctrine-project.org/2013/05/11/doctrine-2-4-beta2.html <![CDATA[Doctrine 2.4 Beta2 released]]>

Doctrine 2.4 Beta2 released

11.05.2013

We have released the second beta version of Doctrine 2.4. Some of the changes are listed in this talk by Alexander and me from Symfony Live Berlin last year.

Most of the new functionality is already documented and marked with “Since 2.4”. We will also prepare a blog post for the release that shows all the new functionality in one place.

You can find a list of changes on Jira.

You can install the release with Composer:

{
    "require": {
        "doctrine/orm": "2.4.0-beta2",
        "doctrine/dbal": "2.4.0-beta2",
        "doctrine/common": "2.4.0-rc2"
    }
}

Please test this release with your existing applications to allow us to find BC breaks and remove them before the final release. This will be the last beta before Release Candidates will be created. We expect to need only one RC and that the final release will follow shortly.

You should make yourself familiar with the UPGRADE documents, as we had to make some backwards compatibility breaks to fix nasty bugs:

]]>
Sat, 11 May 2013 00:00:00 +0000
http://www.doctrine-project.org/2013/05/11/doctrine-2-3-4.html http://www.doctrine-project.org/2013/05/11/doctrine-2-3-4.html <![CDATA[Doctrine 2.3.4 released]]>

Doctrine 2.3.4 released

11.05.2013

We have released version 2.3.4 of Doctrine ORM and DBAL. We fixed as much as 18 DBAL tickets and 12 ORM tickets.

See a Changelog of both components:

You can install the release with PEAR or with Composer:

{
    "require": {
        "doctrine/orm": "2.3.4",
        "doctrine/dbal": "2.3.4"
    }
}
]]>
Sat, 11 May 2013 00:00:00 +0000
http://www.doctrine-project.org/2013/03/24/doctrine-2-4-beta.html http://www.doctrine-project.org/2013/03/24/doctrine-2-4-beta.html <![CDATA[Doctrine 2.4 Beta1 released]]>

Doctrine 2.4 Beta1 released

24.03.2013

We have released the first beta version of Doctrine 2.4. Some of the changes are listed in this talk by Alexander and me from Symfony Live Berlin last year.

You can find a list of changes on Jira.

You can install the release with Composer:

{
    "require": {
        "doctrine/orm": "2.4.0-beta1",
        "doctrine/dbal": "2.4.0-beta1",
        "doctrine/common": "2.4.0-rc1"
    }
}

Please test this release with your existing applications to allow us to find BC breaks and remove them before the final release. The plan is to release the final version in the next 4-6 weeks.

In these next weeks we will work to incorporate all changes in the documentation.

]]>
Sun, 24 Mar 2013 00:00:00 +0000
http://www.doctrine-project.org/2013/03/24/doctrine-2-3-3.html http://www.doctrine-project.org/2013/03/24/doctrine-2-3-3.html <![CDATA[Doctrine 2.3.3 released]]>

Doctrine 2.3.3 released

24.03.2013

We have released a mini version 2.3.3 of ORM and DBAL. See the list of 18 tickets we fixed.

You can install the release with Composer:

{
    "require": {
        "doctrine/orm": "2.3.3",
        "doctrine/dbal": "2.3.3"
    }
}
]]>
Sun, 24 Mar 2013 00:00:00 +0000
http://www.doctrine-project.org/2013/01/08/doctrine-2-3-2.html http://www.doctrine-project.org/2013/01/08/doctrine-2-3-2.html <![CDATA[Doctrine 2.3.2 released]]>

Doctrine 2.3.2 released

08.01.2013

We have released the second mini release in the 2.3 cycle.

You can install the release through Github , download, PEAR or Composer:

{
    "require": {
        "doctrine/orm": "2.3.1"
    }
}
]]>
Tue, 08 Jan 2013 00:00:00 +0000
http://www.doctrine-project.org/2012/12/28/doctrine-orientdb-odm.html http://www.doctrine-project.org/2012/12/28/doctrine-orientdb-odm.html <![CDATA[Doctrine OrientDB Object Document Mapper]]>

Doctrine OrientDB Object Document Mapper

“2012 is the year of graph databases” was the sentence that a lot of people were hearing at the end of 2011, especially after the explosion of Big Data associated with social networks.

At the beginning of this year, a really promising GraphDB, OrientDB , saw its first stable release (1.0.0) which finally gave to the world a stable toy pretty different from the traditional RDBMS that we’re used to see and from the document-based DBs like MongoDB or CouchDB: OrientDB integrates document capabilities with a graph layer, thus it sounded very, very interesting.

Even before going stable, there were some companies already using OrientDB, thanks to the language-specific drivers created by the community surrounding this GraphDB: one of them, for PHP, was Orient , a bunch of classes that wrapped PHP’s native cURL functions to make queries against OrientDB’s via the HTTP protocol.

Day after day, the guys behind Orient, this PHP library, decided to add - mostly inspired by the doctrine 1 query builder and the Doctrine2 ODMs - abstraction and layers over that bunch of classes, finally having 3 different pieces of software to interact with OrientDB from PHP: the HTTP binding, which does HTTP calls to the OrientDB server, the Query Builder, which provides an object-oriented synthax to write SQL+ (OrientDB’s SQL) queries and the Data Mapper, which is still unfinished.

Trying to adhere to the Doctrine2 ODMs standards, the code looks pretty similar:

<?php

// invoking a repository
$userRepository = $manager->getRepository('My\Entity');

// creating SQL+ queries
$query = new Query();
$query->from(array('users'))->where('username = ?', "admin");

// mapping POPOs
namespace Domain;

use Doctrine\ODM\OrientDB\Mapper\Annotations as ODM;

/**
* @ODM\Document(class="Address")
*/
class Address
{
    /**
     * @ODM\Property(type="string")
     */
    public $street;
}

// finding a record
$record = $manager->find($id);

The work done so far was interesting enough to think about an OrientDB ODM inside the Doctrine organization, thing that eventually happened today when the old repository has been moved to the doctrine organization on Github.

More news are going to come in the next weeks, as the target is to release a stable version of the OrientDB ODM this year: you can already use it or even fork it if you want to contribute or propose a patch.

For further informations you can subscribe to the doctrine-dev google group or join the IRC channel #doctrine-dev on Freenode.

]]>
Fri, 28 Dec 2012 00:00:00 +0000
http://www.doctrine-project.org/2012/12/05/doctrine-2-3-1.html http://www.doctrine-project.org/2012/12/05/doctrine-2-3-1.html <![CDATA[Doctrine 2.3.1 relased]]>

Doctrine 2.3.1 relased

05.12.2012

We have released the first mini release in the 2.3 cycle. Due to high workload of all the participating developers we couldn’t release this earlier. We hope to release 2.3.2 in a much shorter period from now.

You can install the release through Github , download, PEAR or Composer:

{
    "require": {
        "doctrine/orm": "2.3.1"
    }
}
]]>
Wed, 05 Dec 2012 00:00:00 +0000
http://www.doctrine-project.org/2012/09/20/doctrine-2-3-final.html http://www.doctrine-project.org/2012/09/20/doctrine-2-3-final.html <![CDATA[Doctrine 2.3 final relased]]>

Doctrine 2.3 final relased

20.9.2012

After a 2 month long phase of beta and release candidates we can finally announce the release of Doctrine 2.3. This includes new versions for the packages Common, DBAL and ORM.

This release trys to keep backwards compatibility to every previous release as much as possible, however some slight changes might be necessary to your applications. See the UPGRADE files of each project for details:

Compared to previous versions there are no new blockbuster feature, but many little optimizations:

  • Custom ID Generators
  • Naming Strategies (Camel-, Underscore Cased)
  • Collection Criteria API
  • @AssociationOverride and @AttributeOverride (useful for Trait and MappedSuperclass)
  • Arbitrary JOIN Syntax (FROM User u JOIN Comment c WITH c.user = u.id)
  • Named Native Queries

The complete changelogs are listed on JIRA:

We will flesh out the documentation and information about all new features in the coming month. If you want to contribute to the documentation of new features see the DBAL and ORM documentation links on Github.

You can install the final release through Github or Composer:

{
    "require": {
        "doctrine/orm": "2.3.0"
    }
}

The downloadable packages will be available later today.

]]>
Thu, 20 Sep 2012 00:00:00 +0000
http://www.doctrine-project.org/2012/09/17/doctrine-2-3-rc4.html http://www.doctrine-project.org/2012/09/17/doctrine-2-3-rc4.html <![CDATA[Doctrine 2.3.0 RC4 released]]>

Doctrine 2.3.0 RC4 released

17.9.2012

We released another release candidate of our upcoming Doctrine 2.3.0 version. This includes the Common, DBAL and ORM packages.

This release trys to keep backwards compatibility to every previous release as much as possible, however some slight changes might be necessary to your applications. See the UPGRADE files of each project for details:

See the 2.3 Beta blog post for some information about changes in 2.3.

You can install the release candidate through Github or Composer:

{
    "require": {
        "doctrine/orm": "2.3.0-RC4"
    },
    "minimum-stability": "dev"
}

If you find any problems with your applications please report them on our bugtracker.

We hope to release the final version of Doctrine 2.3 after this release candidate. Please test your applications with this.

]]>
Mon, 17 Sep 2012 00:00:00 +0000
http://www.doctrine-project.org/2012/09/05/doctrine-2-3-rc3.html http://www.doctrine-project.org/2012/09/05/doctrine-2-3-rc3.html <![CDATA[Doctrine 2.3.0 RC3 released]]>

Doctrine 2.3.0 RC3 released

5.9.2012

We released another release candidate of our upcoming Doctrine 2.3.0 version. This includes the Common, DBAL and ORM packages.

This release trys to keep backwards compatibility to every previous release as much as possible, however some slight changes might be necessary to your applications. See the UPGRADE files of each project for details:

See the 2.3 Beta blog post for some information about changes in 2.3.

You can install the release candidate through Github or Composer:

{
    "require": {
        "doctrine/orm": "2.3.0-RC3"
    },
    "minimum-stability": "dev"
}

If you find any problems with your applications please report them on our bugtracker.

When no blocking issues occur we will release the 2.3.0 final on the weekend.

]]>
Wed, 05 Sep 2012 00:00:00 +0000
http://www.doctrine-project.org/2012/08/29/doctrine-2-3-rc2.html http://www.doctrine-project.org/2012/08/29/doctrine-2-3-rc2.html <![CDATA[Doctrine 2.3.0 RC2 released]]>

Doctrine 2.3.0 RC2 released

29.8.2012

We released another release candidate of our upcoming Doctrine 2.3.0 version. This includes the Common, DBAL and ORM packages.

This release trys to keep backwards compatibility to every previous release as much as possible, however some slight changes might be necessary to your applications. See the UPGRADE files of each project for details:

See the 2.3 Beta blog post for some information about changes in 2.3.

You can install the release candidate through Github or Composer:

{
    "require": {
        "doctrine/orm": "2.3.0-RC2"
    },
    "minimum-stability": "dev"
}

If you find any problems with your applications please report them on our bugtracker.

When no blocking issues occur we will release the 2.3.0 final on next Monday.

]]>
Wed, 29 Aug 2012 00:00:00 +0000
http://www.doctrine-project.org/2012/07/16/doctrine-2-3-beta.html http://www.doctrine-project.org/2012/07/16/doctrine-2-3-beta.html <![CDATA[Doctrine 2.3 Beta]]>

Doctrine 2.3 Beta

16.7.2012

We tagged the Doctrine 2.3 BETA1 release today. This includes tags for the Common, DBAL and ORM projects.

This release trys to keep backwards compatibility to every previous release as much as possible, however some slight changes might be necessary to your applications. See the UPGRADE files of each project for details:

This new release contains not single blockbuster feature, but very many little ones:

  • Custom ID Generators
  • Naming Strategies
  • Collection Criteria API
  • @AssociationOverride and @AttributeOverride (useful for Trait and MappedSuperclass)
  • Arbitrary JOIN Syntax (FROM User u JOIN Comment c WITH c.user = u.id)
  • Named Native Queries

We will flesh out the documentation and information about all new features in the coming beta phase. We hope to release the final version of Doctrine 2.3 just before the upcoming Symfony 2.1 release.

Please test this release with your applications and provide us with feedback about issues that you find.

You can install the Beta through Github or Composer:

{
    "require": {
        "doctrine/orm": "2.3.0-BETA1"
    }
}
]]>
Mon, 16 Jul 2012 00:00:00 +0000
http://www.doctrine-project.org/2012/05/29/symfony-live-2012-hackday.html http://www.doctrine-project.org/2012/05/29/symfony-live-2012-hackday.html <![CDATA[Symfony Live 2012 Hackday]]>

Symfony Live 2012 Hackday

Next week will be Symfony Live 2012 in Paris and the Doctrine DBAL/ORM Team will be represented by Guilherme, Alexander, Marco and me. Jeremy is also there and knows the MongoDB ODM inside out.

Guilherme and Jeremy will give two talks:

  • “Using MongoDB responsibly” Jeremy Mikola
  • “ORMs don’t kill your database, developers do!” Guilherme Blanco

Additionally all of us will participate in the hackday on saturday.

Doctrine 2.3 is around the corner (propably during July) and we still have some features that we want to finalize and work on together. Feel free to join us if you want to contribute. We are always looking for interested developers that help with tickets, support, documentatation or anything else.

During the conference you can find us by looking for the dark blue Doctrine t-shirts.

]]>
Tue, 29 May 2012 00:00:00 +0000
http://www.doctrine-project.org/2012/05/28/doctrine-2-1-7-released.html http://www.doctrine-project.org/2012/05/28/doctrine-2-1-7-released.html <![CDATA[Doctrine 2.1.7 released]]>

Doctrine 2.1.7 released

We released version 2.1.7 of the Doctrine ORM and DBAL today, fixing a total of 18 bugs.

You can install the release through Github , PEAR , download from the website or through Composer:

{
    "require":
    {
        "doctrine/orm": "2.1.7"
    }
}
]]>
Mon, 28 May 2012 00:00:00 +0000
http://www.doctrine-project.org/2012/04/13/doctrine-2-2-2-released.html http://www.doctrine-project.org/2012/04/13/doctrine-2-2-2-released.html <![CDATA[Doctrine 2.2.2 released]]>

Doctrine 2.2.2 released

We released version 2.2.2 of the Doctrine ORM, Common and DBAL today, fixing a total of 20 bugs.

You can install the release through Github , PEAR , download from the website or through Composer:

{
    "require": {
        "doctrine/orm": "2.2.2"
    }
}
]]>
Fri, 13 Apr 2012 00:00:00 +0000
http://www.doctrine-project.org/2012/03/07/new-doctrine-website.html http://www.doctrine-project.org/2012/03/07/new-doctrine-website.html <![CDATA[New Website]]>

New Website

]]>
Wed, 07 Mar 2012 00:00:00 +0000
http://www.doctrine-project.org/2012/03/04/doctrine-2-2-1-released.html http://www.doctrine-project.org/2012/03/04/doctrine-2-2-1-released.html <![CDATA[Doctrine 2.2.1 released]]>

Doctrine 2.2.1 released

We released version 2.2.1 of the Doctrine ORM today, fixing a total of 16 bugs.

You can install the release through Github , PEAR , download from the website or through Composer:

{

“require”: {

“doctrine/orm”: “2.2.1”

}

}

]]>
Sun, 04 Mar 2012 00:00:00 +0000
http://www.doctrine-project.org/2012/01/30/doctrine-2-1-6.html http://www.doctrine-project.org/2012/01/30/doctrine-2-1-6.html <![CDATA[DBAL/ORM 2.1.6 released]]>

DBAL/ORM 2.1.6 released

We released a new round of maintenance releases for the 2.1 branch. DBAL and ORM are now in version 2.1.6 of their lifecycle. There have been 8 bug fixes in ORM and 8 in DBAL. See the changelogs:

As usual code is available via Download, PEAR, Packagist/Composer or from Github.

]]>
Mon, 30 Jan 2012 00:00:00 +0000
http://www.doctrine-project.org/2012/01/29/doctrine-2-2-final.html http://www.doctrine-project.org/2012/01/29/doctrine-2-2-final.html <![CDATA[Doctrine 2.2 released]]>

Doctrine 2.2 released

We released Doctrine 2.2 today.

A top list of the new features includes:

  • Filtering entities and associations based on rules that can be parameterized, enabled or disabled, developed by asm89
  • Support for complex SQL types such as Geometries, IPs, develped by jsor.
  • Bit Comparisions in DQL, developed by Fabio.
  • Annotation Refactorings by Fabio and johannes.
  • DQL Refactoring, ORDER BY and GROUP BY supporting result variables of SELECT expressions.
  • Alias for entities in DQL results.
  • Result Cache refactoring
  • Flush for single entities
  • Master/Slave Connection in DBAL

See the changelogs of all three projects Common, DBAL, ORM:

See the UPGRADE_2_2 file to see backwards incompatible changes.

You can install the release through Github , PEAR or through Composer:

{

“require”: {

“doctrine/orm”: “2.2.0”

}

}

]]>
Sun, 29 Jan 2012 00:00:00 +0000
http://www.doctrine-project.org/2012/01/22/dbal-orm-22rc1.html http://www.doctrine-project.org/2012/01/22/dbal-orm-22rc1.html <![CDATA[DBAL and ORM 2.2 Release candidates]]>

DBAL and ORM 2.2 Release candidates

Again with a slight delay we finalized the DBAL and ORM release candidates for the 2.2 branch. There have been some late changes that made the delay necessary:

  • DBAL Schema supported was heavily refactored to include the concept of “namespaces”. This abstracts multi-database useage for MySQL and Schema support for PostgreSQL.
  • A Paginator was put into the DoctrineORMToolsPagination namespace. Its the combination of the original DoctrineExtensions Paginator with extensions done in the KnpLabs components and the Pagerfanta library.

As usual you can grab the code from:

Please test this code with your applications. If no bugs or backwards-compatible breaks are reported in the next days we will release the final version on friday.

]]>
Sun, 22 Jan 2012 00:00:00 +0000
http://www.doctrine-project.org/2012/01/03/doctrine2-2-beta2.html http://www.doctrine-project.org/2012/01/03/doctrine2-2-beta2.html <![CDATA[Doctrine 2.2 Beta 2]]>

Doctrine 2.2 Beta 2

Sadly we did not manage to hold our schedule with a 2.2 release in 2011, we had to do some larger changes before the final release. This means we are releasing another Beta of Doctrine DBAL and ORM. The final release is rescheduled to 19th January.

Please try and test this code with your production applications and report any backwards compatibility breaks to the Bug Tracker or the Mailing List. See the UPGRADE_2_2 file to see backwards incompatible changes.

You can install the Beta through Github , PEAR by download or through Composer:

{

“require”: {

“doctrine/orm”: “2.2.0-BETA2”

}

}

]]>
Tue, 03 Jan 2012 00:00:00 +0000
http://www.doctrine-project.org/2011/12/20/doctrine2-2-beta.html http://www.doctrine-project.org/2011/12/20/doctrine2-2-beta.html <![CDATA[Doctrine 2.2 Beta]]>

Doctrine 2.2 Beta

We are proud to announce the start of the beta phase of Doctrine 2.2. I think we implemented a nice amount of new features and refactored lots of the code-base for simplicity and performance. Additionally we found a bunch of new developers that contributed considerable amount of code.

A top list of the changes includes:

  • Filtering entities and associations based on rules that can be parameterized, enabled or disabled, developed by asm89
  • Support for complex SQL types such as Geometries, IPs, develped by jsor.
  • Bit Comparisions in DQL, developed by Fabio.
  • Annotation Refactorings by Fabio and johannes.
  • DQL Refactoring, ORDER BY and GROUP BY supporting result variables of SELECT expressions.
  • Alias for entities in DQL results.
  • Result Cache refactoring
  • Flush for single entities

See the changelogs of all three projects Common, DBAL, ORM:

In the next weeks will stabilize this code and add documentation for all the new features. Additionally we try to drive the bug count down in the 2.1 branch as well.

Please test this beta with your projects to find any incompatibilities. See the UPGRADE_2_2 file to see backwards incompatible changes.

You can install the Beta through Github , `PEAR http://pear.doctrine-project.org>`_ or through Composer:

{

“require”: {

“doctrine/orm”: “2.2.0-BETA1”

}

}

]]>
Tue, 20 Dec 2011 00:00:00 +0000
http://www.doctrine-project.org/2011/12/19/doctrine-2-1-5.html http://www.doctrine-project.org/2011/12/19/doctrine-2-1-5.html <![CDATA[Doctrine ORM 2.1.5 released]]>

Doctrine ORM 2.1.5 released

We released another Doctrine ORM bugfix release, version 2.1.5. It fixes 5 critical regressions that were introduced in 2.1.0, 2.1.2 and 2.1.3 and a total of 10 issues. See the changelog for details.

You can get the code from PEAR , the download section or directly from `Github <https://github.com/doctrine/doctrine2/tree/2.1.5`_.

]]>
Mon, 19 Dec 2011 00:00:00 +0000
http://www.doctrine-project.org/2011/12/15/symfony-bundles-move.html http://www.doctrine-project.org/2011/12/15/symfony-bundles-move.html <![CDATA[Our Symfony Bundles move to Doctrine organization]]>

Our Symfony Bundles move to Doctrine organization

Note

Important first point: This move does not affect Symfony 2.0 apps at all, only the Symfony master is affected.

The Symfony2 Doctrine related Bundles move to the Doctrine organization. The DoctrineBundle being in the core for the 2.0 release it is now maintained in a more decoupled way from Symfony for several reasons:

  • No coupling of release cycles anymore.
  • Move code to the organization that actually maintains it.
  • Avoid Symfony suggesting Doctrine is the only way for persistence, Symfony wants to focus on providing View and Controller and not make suggestions about the model.

The DoctrineFixturesBundle, DoctrineMigrationsBundle and DoctrineMongoDBBundle are now maintained in the Doctrine organization, however forks have been created in the Symfony repository to make all the 2.0 apps out there backwards compatible. You find the new repositories here:

What do you need to change in your code? Not very much. For the DoctrineBundle for example the following:

  • Update the deps file to include the DoctrineBundle

    [empty]
    [DoctrineBundle]
        git=http://github.com/doctrine/DoctrineBundle.git
        target=/bundles/Doctrine/Bundle/DoctrineBundle
    
  • Change the Bundle class

    $bundles = array(
        //..
        new Doctrine\Bundle\DoctrineBundle\DoctrineBundle(),
        //..
    );
    
  • Change references to Registry

The SymfonyBundleDoctrineBundleRegistry class may be type-hinted in your code. You have to change this code to point to DoctrineBundleDoctrineBundleRegistry.

A full deps file for all Doctrine bundles now looks like:

[empty]
[data-fixtures]
    git=http://github.com/doctrine/data-fixtures.git

[migrations]
    git=http://github.com/doctrine/migrations.git

[DoctrineBundle]
    git=http://github.com/doctrine/DoctrineBundle.git
    target=/bundles/Doctrine/Bundle/DoctrineBundle

[DoctrineMigrationsBundle]
    git=http://github.com/doctrine/DoctrineMigrationsBundle.git
    target=/bundles/Doctrine/Bundle/MigrationsBundle

[DoctrineFixturesBundle]
    git=http://github.com/doctrine/DoctrineFixturesBundle.git
    target=/bundles/Doctrine/Bundle/FixturesBundle

And the autoload.php:

$loader->registerNamespaces(array(
    'Symfony'          => array(__DIR__.'/../vendor/symfony/src', __DIR__.'/../vendor/bundles'),
    'Sensio'           => __DIR__.'/../vendor/bundles',
    'JMS'              => __DIR__.'/../vendor/bundles',
    'Doctrine\\Bundle' => __DIR__.'/../vendor/bundles',
    'Doctrine\\DBAL\\Migrations' => __DIR__.'/../vendor/migrations/lib',
    'Doctrine\\Common\\DataFixtures' => __DIR__.'/../vendor/data-fixtures/lib',
    'Doctrine\\Common' => __DIR__.'/../vendor/doctrine-common/lib',
    'Doctrine\\DBAL'   => __DIR__.'/../vendor/doctrine-dbal/lib',
    'Doctrine'         => __DIR__.'/../vendor/doctrine/lib',
    'Monolog'          => __DIR__.'/../vendor/monolog/src',
    'Assetic'          => __DIR__.'/../vendor/assetic/src',
    'Metadata'         => __DIR__.'/../vendor/metadata/src',
));

And the Kernel:

$bundles = array(
    new Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
    new Symfony\Bundle\SecurityBundle\SecurityBundle(),
    new Symfony\Bundle\TwigBundle\TwigBundle(),
    new Symfony\Bundle\MonologBundle\MonologBundle(),
    new Symfony\Bundle\SwiftmailerBundle\SwiftmailerBundle(),
    new Symfony\Bundle\AsseticBundle\AsseticBundle(),
    new Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle(),
    new JMS\SecurityExtraBundle\JMSSecurityExtraBundle(),
    new Doctrine\Bundle\DoctrineBundle\DoctrineBundle(),
    new Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle(),
    new Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle(),
);
]]>
Thu, 15 Dec 2011 00:00:00 +0000
http://www.doctrine-project.org/2011/11/23/doctrine-orm-2-1-4-released.html http://www.doctrine-project.org/2011/11/23/doctrine-orm-2-1-4-released.html <![CDATA[Doctrine ORM 2.1.4 released]]>

Doctrine ORM 2.1.4 released

I just released Doctrine ORM 2.1.4. The Doctrine ORM 2.1.3 release has a regression in the EntityManager#merge() method, which is fixed in this release. See the changelog.

Get the package from PEAR , Downloads or from Github.

]]>
Wed, 23 Nov 2011 00:00:00 +0000
http://www.doctrine-project.org/2011/11/21/doctrine-maintenance-nov2011.html http://www.doctrine-project.org/2011/11/21/doctrine-maintenance-nov2011.html <![CDATA[Doctrine Common 2.1.3, DBAL 2.1.5 and ORM 2.1.3 Releases]]>

Doctrine Common 2.1.3, DBAL 2.1.5 and ORM 2.1.3 Releases

The bugfix release is three weeks overdue, here is it now:

The security fix concerns usage of the ASC/DESC orientation parameters in $repository->findBy($criteria, $orderBy), which is subject to SQL injection when user-input is allowed into this method.

You can grab the downloads from the project page , via PEAR or Git

Please update your installations.

]]>
Mon, 21 Nov 2011 00:00:00 +0000
http://www.doctrine-project.org/2011/11/21/a-doctrine-orm-odm-base-class.html http://www.doctrine-project.org/2011/11/21/a-doctrine-orm-odm-base-class.html <![CDATA[An ORM/ODM Base Class]]>

An ORM/ODM Base Class

One of most common complaints about Doctrine2 is the requirement to write getters/setters for all the fields and assocations of every entity. A concern that immediately follows is that Doctrine 2 is not suitable for Rapid-Application-Development.

The problem is purely a usability concern and there are a bunch of very easy ways ouf of this problem:

  • A base-object that has __get/__set.
  • The EntityGenerator can generate getters/setters
  • An IDE that generates getters/setters (Netbeans, PHPStorm)

We have been very critical of ActiveRecord since we started the development of Doctrine 2 for various reasons. Mostly because we don’t think coupling the database to your domain objects is a good choice for testability an maintainabilty reasons.

However we do see the need for Doctrine 2 to be suitable for RAD projects. With the launch of Symfony2 and other frameworks with tight Doctrine 2 integration this requirement has become even more important.

That is why we will introduce a very lightweight base-class into Doctrine. We managed to write this base-class on an abstract level against the Common Metadata interface, such that CouchDB-, MongoDB- and PHPCR-ODM implementations benefit from this as well.

Using a new hook in Doctrine 2.2-DEV you can now inject the EntityManager (ObjectManager) and the metadata description into each entity during construction. This metadata is used to implement the magic __call hook implementing getters/setters and association management methods.

Example

A simple example will demonstrate this:

<?php use DoctrineCommonPersistencePersistentObject; use DoctrineORMEntityManager;

/**
  • @Entity

**/

class User extends PersistentObject {

/** @Id @Column(type=”integer”) @GeneratedValue **/ protected $id;

/** @Column(type=”string”) **/ protected $name;

/** @OneToMany(targetEntity=”Phonenumber”, mappedBy=”user”) **/ protected $phonenumbers;

}

Extending from PersistentObject will make getters/setters available for your entities. Bi-directional associations are handled automatically.

<?php
/**
 * @Entity
 **/
class Phonenumber extends PersistentObject
{
    /** @Id @Column(type="string") **/
    private $number;

    /** @ManyToOne(targetEntity="User", inversedBy="phonenumbers") **/
    private $user;
}

The only configuration call for the PersistentObject is a registration of the responsible entity/document manager:

<?php
$entityManager = EntityManager::create(...);
PersistentObject::setObjectManager($entityManager);

You can now start using the entities as simple as this:

<?php
$number = new Phonenumber();
$number->setNumber(123454);
$user = new User();
$user->setName("Benjamin");
$user->addPhonenumbers($number);

echo $user->getName();
foreach ($user->getPhonenumbers() AS $number) {
    echo $number->getNumber();
}

Future Developments

First important notice: We will not develop the PersistentObject into a full-fledged active record. Doctrine focuses on being a DataMapper. We do however provide a bunch of new hooks in version 2.2 that will allow you to turn Doctrine 2 into an active record very easily:

  • Inject EntityManager and ClassMetadata

If your entity implements DoctrineCommonPersistentObjectManagerAware then the ObjectManager and ClassMetadata of the entity will be injected during construction.

  • EntityManager#flush() can now flush one entity only

When you pass a single entity to EntityManager#flush() this entity will be the only one flushed into the database. Cascade persist rules are applied to this object. With this feature and access to the EntityManager inside your entities you can now start implementing an efficient Active Record with “Record#save()” and “Record#delete()” methods.

  • PHP 5.4 and Traits

The next version of PHP is already in Beta 2 and will probably be released in the next months. One of the most powerful feature of this release will be Traits, something very suitable for Doctrine and ORMs in general.

No worries: Doctrine 2 will always be supporting 5.3, however we will probably ship with optional features that are using the trait functionality. High on the list:

  • Porting PersistentObject to a trait
  • Serialization of entities from a trait (ToArray(), ToJson()). Available as a service to PHP 5.3
  • ActiveEntity trait that extends the PersistentObject one.

Based on this feature set it should even be possible to add behaviors to Doctrine 2, although we won’t focus on implementing behaviors in the core team.

Last words

I would really appreciate people starting to test the PersistentObject if they like too and give us feedback.

]]>
Mon, 21 Nov 2011 00:00:00 +0000
http://www.doctrine-project.org/2011/09/25/doctrine-maintenance-sep2011.html http://www.doctrine-project.org/2011/09/25/doctrine-maintenance-sep2011.html <![CDATA[Maintenance 2.1 Releases for Common, DBAL and ORM and DBAL 2.0.9]]>

Maintenance 2.1 Releases for Common, DBAL and ORM and DBAL 2.0.9

We have released the maintenance versions Common 2.1.2, DBAL 2.1.3 and ORM 2.1.2.

A total of 20 bugs have been fixed in all 3 components. The DBAL release contains a security fix for the Oracle driver fixing a possible SQL injection issue. If you are using Oracle please update immediately. This security fix was backported to 2.0 and a new 2.0.9 version was released.

]]>
Sun, 25 Sep 2011 00:00:00 +0000
http://www.doctrine-project.org/2011/08/29/dbal-security-2011-1.html http://www.doctrine-project.org/2011/08/29/dbal-security-2011-1.html <![CDATA[Security releases 2.0.8 and 2.1.2]]>

Security releases 2.0.8 and 2.1.2

It was brought to our attention that identifier quoting in Doctrine DBAL has a potential security problem when user-input is passed into this function, making the security aspect of this functionality obsolete. We fixed as soon as we realized it and apologize for to our users for this error.

We released versions 2.1.2 and 2.0.8 of DBAL that both contain a fix for the problem. You can grab the code from PEAR , Github or the Downloads section.

If you make use of AbstractPlatform::quoteIdentifier() or Doctrine::quoteIdentifier() please upgrade immediately. The ORM itself does not use identifier quoting in combination with user-input, however we still urge everyone to update to the latest version of DBAL.

]]>
Mon, 29 Aug 2011 00:00:00 +0000
http://www.doctrine-project.org/2011/08/26/doctrine2-1-1.html http://www.doctrine-project.org/2011/08/26/doctrine2-1-1.html <![CDATA[DBAL and ORM 2.1.1 maintenance releases]]>

DBAL and ORM 2.1.1 maintenance releases

We released the DBAL and ORM 2.1.1 maintenance versions today that several issues with both packages. You can see the changelog of both packages on Jira:

Please report any problems with these packages to the Jira tracker or the mailing list.

You can download the packages through PEAR or our download sections within each project.

]]>
Fri, 26 Aug 2011 00:00:00 +0000
http://www.doctrine-project.org/2011/08/17/doctrine-2-0-7-and-eol.html http://www.doctrine-project.org/2011/08/17/doctrine-2-0-7-and-eol.html <![CDATA[Doctrine 2.0.7 and EOL]]>

Doctrine 2.0.7 and EOL

We released the last maintenance version of the 2.0.x branch Doctrine 2.0.7 today. It contains a bunch of fixes backported from the 2.1.x and master branches. You can find the list of fixes in the Changelog:

This release marks the end of line of the 2.0.x branch. We will not port bugs for this branch anymore only security issues will get applied. Please upgrade to 2.1.1 when it will be released later this week. The upgrade to 2.1 is painless and the small number of backwards incompatible changes is documented. Also most of the BC related bugs in the 2.1.0 release will be fixed in 2.1.1.

]]>
Wed, 17 Aug 2011 00:00:00 +0000
http://www.doctrine-project.org/2011/07/04/doctrine-2-1.html http://www.doctrine-project.org/2011/07/04/doctrine-2-1.html <![CDATA[Doctrine 2.1 released]]>

Doctrine 2.1 released

We finished all the outstanding work on the Doctrine 2.1 branch and released the first final version. Almost all of the code was kept backwards compatible. There are only some slight changes that are explained in the UPGRADE_TO_2_1 file.

This release is packed with new features and optimizations:

  • Indexed associations: You can force Doctrine to hydrate collection elements by using a field of the target entity as key, for example the ID or any unique field. See the tutorial for this feature.
  • Extra Lazy Collections: Instead of always initializing the complete collection in memory you can now mark a collection as extra lazy, leading to special SQL executed for Collection#count(), Collection#contains() and Collection#slice(). This allows to implement efficient pagination on collections without having to use DQL. It also allows to save some memory for common use-cases with very large collections. See the tutorial for this feature.
  • Identity through Foreign Entities or derived entities: You can now use a foreign key as identifier of an entity. This translates to using @Id on a @ManyToOne or @OneToOne association. You can read up on this feature in the tutorial.
  • Persister Refactoring: Instead of reimplementing hydration in the persisters we now use the hydration mechanism that is used by DQL aswell. Sadly this drops performance for hydration in the persisters by 5-25% for some use-cases. It starts with a drop of 5% for a few hydrations and increases in the number of different hydrations you are doing in a request. As a benefit we could remove tons of code and use several optimizations that actually increase performance when using fetch=”EAGER” in ManyToOne and OneToOne associations. Furthermore inverse OneToOne associations previously always executed an additional query, which is now replaced with a join.
  • Temporary fetch mode in DQL On a DQL Query you can now call :math:`$query->setFetchMode($`className, $assocName, $fetchMode) to temporarily set the fetch mode to a value different from the one defined in the Association Mapping. If you set a ManyToOne or OneToOne association to eager fetching Doctrine will use a batch WHERE id IN (..) query to fetch all entities in a single query after the original query was completed.
  • Binding Arrays to a Query: Doctrine now implements low-level support for binding arrays to named or positional parameters. This is possible with the Doctrine::TYPE_INT_ARRAY and Doctrine::TYPE_STR_ARRAY parameters that you have to pass as types to a query you want to use this feature in. EntityRepository now supports passing arrays as values to a field and uses an IN query.
  • EntityRepository Limit and OrderBy: The method EntityRepository#findBy() now accepts additional parameters for ordering, limit and offset.
  • ResultSetMapping Helper: There is now a class that simplifies populating a ResultSetMapping based on an existing ClassMetadata instance.
  • Zero Based Parameters in Queries: You can now start with the parameter ?0 in DQL queries.
  • Named DQL Queries in Metadata: You can add dql queries in the mapping files using @NamedQueries(@NamedQuery(name=”foo”, query=”DQL”)) and access them through $em->getRepository()->getNamedQuery().
  • Date related DQL functions: Suport for DATE_ADD(), DATE_SUB() and DATE_DIFF() in DQL.
  • New console command orm:info: Gives details about all registered entities and if their mappings are valid or not.
  • Read Only Entities: You can set the attribute readOnly=true on an entity. This will only allow to persist new instances of this entity or removing them, they will never be considered for updating, thus allowing for performance optimizations where these entities are not considered in the UnitOfWork changeset computations.
  • SQL Query Object: There is now an SQL Query object in the Doctrine project. You can create an instance with $connection->createQueryBuilder().
  • Automatic Parameter Type Inference: For certain parameters types such as integer and DateTime ORM Query::setParameter can now automatically infer the type instead of requiring manually passing the values as third parameter.
  • AnnotationReader Refactoring - The annotation reader is now much more powerful and also allows for giving you error advices if you configure it this way. See the documentation on all the changes and how Annotations work in 2.1.

See the changelogs for a list of all changes:

You can grab the code from our downloads section , from PEAR or directly from Github.

I will announce winners of the backwards compatibility competition in the next weeks and send out gifts. The team thanks all contributors and bug-reporters for helping making Doctrine 2.1 a stable release. The next release of Doctrine 2.2 is scheduled for December 2011. We havent quite made up our mind on the roadmap yet, but expect a post on this issue soon.

]]>
Mon, 04 Jul 2011 00:00:00 +0000
http://www.doctrine-project.org/2011/07/02/doctrine-2-1-rc3.html http://www.doctrine-project.org/2011/07/02/doctrine-2-1-rc3.html <![CDATA[Doctrine 2.1 Release Candidate 3]]>

Doctrine 2.1 Release Candidate 3

We released Doctrine 2.1 Release Candidate 3 after some important changes to the new annotation reader. That is also why we didnt manage to keep our release date of June 30th. The new date is Monday.

About the Annotations: We constantly had problems with the autoloading of annotations through PHP autoloaders, increasing with Symfony2 starting to use the reader with enabled autoloading. The problem with reusing the PHP autoloader can be explained easily: Not every Docblock Annotation has a corresponding PHP class that can be instantiated by Doctrines AnnotationReader. The question is how we detect the annotations from the documentation related comments only. The solution required a silent autoloader, meaning no failure should occur if an autoload is triggered for a non-existant class. Implementing such an autoloader has performance drawbacks though, which is why the Doctrine does not fail silently. Autoloading annotations was not compatible with Doctrines own class loader.

That problem is why we removed PHP autoloading completely and reimplemented our own autoloading mechanism inside Doctrine Annotations. Now we have much more control about when errors occur and if we skip them or throw an exception.

See this following Gist on how autoloading annotations works. This is not relevant if you use $config->newDefaultAnnotationDriver() with the ORM though, which will handle all the necessary bootstrapping for you.

Additionally we have changed the annotation reader in other aspects. To be a valid annotation your class have to extend (backwards compatible way, will be removed in 3.0.x) or contain @Annotation inside the class level docblock.

We will update the documentation for Doctrine Common accordingly in the next hours to allow you to understand all the changes made between 2.0 and 2.1.

If you are using Annotations either in Doctrine 2 or within your own code please update and check the changes.

]]>
Sat, 02 Jul 2011 00:00:00 +0000
http://www.doctrine-project.org/2011/06/28/doctrine-2-1-rc2.html http://www.doctrine-project.org/2011/06/28/doctrine-2-1-rc2.html <![CDATA[Doctrine 2.1 Release Candidate 2]]>

Doctrine 2.1 Release Candidate 2

RC2 of Doctrine 2.1 is packaged and can be grabbed from PEAR and the download section.

We fixed several inconsistencies, backwards compatibility breaks and some bugs.

Please test this release as it will probably be the base of the final release due to be released later this week. The scheduled date is Thursday 30th, but due to personal timetable this may become the weekend.

]]>
Tue, 28 Jun 2011 00:00:00 +0000
http://www.doctrine-project.org/2011/06/18/doctrine-2-1-rc1.html http://www.doctrine-project.org/2011/06/18/doctrine-2-1-rc1.html <![CDATA[Doctrine 2.1 Release Candidate 1]]>

Doctrine 2.1 Release Candidate 1

Doctrine 2.1 is feature complete and we packaged up the first release candidate to celebrate this day. So far we got exactly one backwards compability complaint that was immediately fixed. You only have about 10 days to verify that this release candidate is working with your existing 2.0 code-bases. If you find some problems please report a bug on Jira. We will provide everyone with mugs/tshirts who is finding incompatible changes.

We plan to release only 1-2 bugfix releases of the 2.0.x branch, which should give you lots of motivation to try out 2.1 with your projects.

We integrated a pretty substantial Annotation Reader refactoring just today. Please test if this still works with your code-base using annotations. See the UPGRADE_TO_2_1 file for some information. You might need to adjust your bootstrapping code to get it working.

The task now until the final release on june 30th will be to update the documentation with all the changes that have landed in Doctrine 2.1. We already created a 2.0.x branch of the docs that will freeze the current state for those staying on 2.0. Additionally we will squash all the last bugs that we find.

Grab the new code in the downloads section or on our PEAR channel

]]>
Sat, 18 Jun 2011 00:00:00 +0000
http://www.doctrine-project.org/2011/06/17/doctrine-2-0-6.html http://www.doctrine-project.org/2011/06/17/doctrine-2-0-6.html <![CDATA[Doctrine 2.0.6 DBAL and ORM Releases]]>

Doctrine 2.0.6 DBAL and ORM Releases

On wednesday we released Doctrine 2.0.6 of DBAL and ORM. Both versions include some bugfixes, DBAL for identifier quoting with MSSQL and issues with cascade remove, inheritance and the XML driver for the ORM.

See the changelogs for more details:

Grab the download from our PEAR Channel or from the download section of our website.

]]>
Fri, 17 Jun 2011 00:00:00 +0000
http://www.doctrine-project.org/2011/05/16/doctrine-2-1-beta-release.html http://www.doctrine-project.org/2011/05/16/doctrine-2-1-beta-release.html <![CDATA[Doctrine 2.1 Beta and Backwards Compatibility Competition]]>

Doctrine 2.1 Beta and Backwards Compatibility Competition

We would like to announce the first beta release of Doctrine 2.1. It is packed with new features that will make your life easier:

  • Indexed associations: You can force Doctrine to hydrate collection elements by using a field of the target entity as key, for example the ID or any unique field. See the tutorial for this feature.
  • Extra Lazy Collections: Instead of always initializing the complete collection in memory you can now mark a collection as extra lazy, leading to special SQL executed for Collection#count(), Collection#contains() and Collection#slice(). This allows to implement efficient pagination on collections without having to use DQL. It also allows to save some memory for common use-cases with very large collections. See the tutorial for this feature.
  • Identity through Foreign Entities or derived entities: You can now use a foreign key as identifier of an entity. This translates to using @Id on a @ManyToOne or @OneToOne association. You can read up on this feature in the tutorial.
  • Persister Refactoring: Instead of reimplementing hydration in the persisters we now use the hydration mechanism that is used by DQL aswell. Sadly performance for hydration in the persisters drops by 5-25% for different use-cases. It starts with a drop of 5% for a few hydrations and increases the more hydrations you are doing in a request. As a benefit we could remove tons of code and use several optimizations that actually increase performance when using fetch=”EAGER” in ManyToOne and OneToOne associations. Furthermore inverse OneToOne associations previously always executed an additional query, which is now replaced with a join.
  • Temporary fetch mode in DQL On a DQL Query you can now call :math:`$query->setFetchMode($`className, $assocName, $fetchMode) to temporarily set the fetch mode to a value different from the one defined in the Association Mapping. If you set a ManyToOne or OneToOne association to eager fetching Doctrine will use a batch WHERE id IN (..) query to fetch all entities in a single query.
  • Binding Arrays to a Query: Doctrine now implements low-level support for binding arrays to named or positional parameters. This is possible with the Doctrine::TYPE_INT_ARRAY and Doctrine::TYPE_STR_ARRAY parameters that you have to pass as types to a query you want to use this feature in. EntityRepository now supports passing arrays as values to a field and uses an IN query.
  • EntityRepository Limit and OrderBy: The method EntityRepository#findBy() now accepts additional parameters for ordering, limit and offset.
  • ResultSetMapping Helper: There is now a class that simplifies populating a ResultSetMapping based on an existing ClassMetadata instance.
  • Zero Based Parameters in Queries: You can now start with the parameter ?0 in DQL queries.
  • Named DQL Queries in Metadata: You can add dql queries in the mapping files using @NamedQueries(@NamedQuery(name=”foo”, query=”DQL”)) and access them through $em->getRepository()->getNamedQuery().
  • Date related DQL functions: Suport for DATE_ADD(), DATE_SUB() and DATE_DIFF() in DQL.
  • New console command orm:info: Gives details about all registered entities and if their mappings are valid or not.
  • Read Only Entities: You can set the attribute readOnly=true on an entity. This will only allow to persist new instances of this entity or removing them, they will never be considered for updating, thus allowing for performance optimizations where these entities are not considered in the UnitOfWork changeset computations.
  • SQL Query Object: There is now an SQL Query object in the Doctrine project. You can create an instance with $connection->createQueryBuilder().
  • Automatic Parameter Type Inference: For certain parameters types such as integer and DateTime ORM Query::setParameter can now automatically infer the type instead of requiring manually passing the values as third parameter.

Documentation for all the feature will be updated in the next weeks. The release is planned for June 30th 2011.

With all this new features, some of them requiring large internal refactorings, we want to assure that Doctrine 2.1 is backwards compatible with Doctrine 2.0. Our testsuite ensuring backwards compatibility is very large, but we cannot be sure that we test for every edge case. That is where you as Doctrine-user come into play: Please test Doctrine 2.1 with your applications and give us feedback about backwards compatibility. Please report any problem on Jira or write a mail to the doctrine-user or doctrine-dev mailing list.

Anyone finding a backwards incompatible change gets an honorable mention in the release notes and some may even get small presents! (This only applies to versions >= Doctrine 2.0.0 with no customizations and people living in countries with reasonable shipping rates :-)).

]]>
Mon, 16 May 2011 00:00:00 +0000
http://www.doctrine-project.org/2011/05/14/doctrine-maintenance-may11.html http://www.doctrine-project.org/2011/05/14/doctrine-maintenance-may11.html <![CDATA[Maintenance Releases 2.0.5 for DBAL and ORM]]>

Maintenance Releases 2.0.5 for DBAL and ORM

Slightly behind schedule we released the next round of maintenance versions of Doctrine DBAL (2.0.5) and ORM (2.0.5) today. It also includes a Security fix for DBAL in combination with PDO MySQL and charsets that was closed in PHP 5.3.6. If you are using 5.3.6, you should now use the “charset” option in DriverManager::getConnection() instead of the MysqlSessionInit listener.

You can grab the packages from the download page or our Github repository.

Please report any problems to the Jira Bugtracker.

]]>
Sat, 14 May 2011 00:00:00 +0000
http://www.doctrine-project.org/2011/04/07/doctrine2-april-2011-maintenance.html http://www.doctrine-project.org/2011/04/07/doctrine2-april-2011-maintenance.html <![CDATA[Maintenance Releases of Common, DBAL, ORM]]>

Maintenance Releases of Common, DBAL, ORM

Slightly behind schedule, but we released the next round of maintenance versions of Doctrine Common (2.0.2), DBAL (2.0.4) and ORM (2.0.4) today.

You can grab the packages from the download page or our Github repository.

Please report any problems to the Jira Bugtracker.

]]>
Thu, 07 Apr 2011 00:00:00 +0000
http://www.doctrine-project.org/2011/03/20/doctrine-security-fix.html http://www.doctrine-project.org/2011/03/20/doctrine-security-fix.html <![CDATA[Security Fix: Upgrade to 1.2.4 and 2.0.3 immediately]]>

Security Fix: Upgrade to 1.2.4 and 2.0.3 immediately

Because of a SQL injection possibility we urge users of Doctrine 1.2 and 2 to the newly released versions of both libraries immediately. Both versions only include the security fix and no other changes to their previous versions 1.2.3 and 2.0.2.

Affected versions are:

  • 1.2.3 and earlier for PostgreSQL and DB2 Dialects
  • 2.0.2 and earlier

The security hole was found today and affects the Doctrine\DBAL\Platforms\AbstractPlatform::modifyLimitQuery() function which does not cast input values for limit and offset to integer and allows malicious SQL to be executed if these parameters are passed into Doctrine 2 directly from request variables without previous cast to integer. Functionality building on top using limit queries in the ORM such as Doctrine\ORM\Query::setFirstResult() and Doctrine\ORM\Query::setMaxResults() are also affected by this security hole.

You can grab the packages from PEAR, Archive or Github, see the respective links more details:

The fix for this security hole breaks backwards compatibility for developers that extend the Doctrine\DBAL\Platforms\AbstractPlatform::modifyLimitQuery() method, because it is now marked as final. Please overwrite the Doctrine\DBAL\Platforms\AbstractPlatform::doModifyLimitQuery() method instead.

]]>
Sun, 20 Mar 2011 00:00:00 +0000
http://www.doctrine-project.org/2011/03/06/doctrine-oxm-intro.html http://www.doctrine-project.org/2011/03/06/doctrine-oxm-intro.html <![CDATA[A Doctrine OXM Introduction]]>

A Doctrine OXM Introduction

Greetings programmers!

Some of you may have noticed a new project being hosted by Doctrine’s github named Object XML Mapper(OXM). The OXM is the newest member of the Doctrine family, and serves as persistence and marshalling framework for PHP objects to XML, and back again. I’d like to take a moment to introduce myself, the company I work for, and the pain points behind the project’s inception.

We at Opensoft have always been fans of open source software, and love to give back to the community. I recently was required to implement some vendor specific XML within a corporate PHP application. The XML itself had the following requirements and pain points:

  • 900+ page specification... over 600 unique XML elements.
  • The XML is used as a workflow. Lots of pull xml, alter it slightly, and save it back
  • The XML must be available to the end user upon request.
  • Some of the XML had to be able to be sent via POST to other services, and parse responses back

Working with objects is so much better than working with such complex XML.

As a PHP enthusiest and fan of Doctrine, I created a small project that was capable of marshalling, unmarshalling, and persisting PHP objects to XML using Doctrine Common package as a base, and many ideas from the ORM, and ODM projects. The Java Castor project also brought a lot of ideas to give a high degree of control to the developer during the (un)marshalling process. ClassMetadata is collected for each @XmlEntity class and used to perform the mapping from PHP objects to native XML.

Right now, the API is still quite unstable, but we’re working to change that. Currently Doctrine users should find a lot of familiarity between OXM and other Doctrine initiatives. We’ve tried to stay as close to the Doctrine ways of doing things as possible. If you feel like this project could help you make working with XML better, please send me a line, fork the project, and send some pull requests!

Enjoy!

]]>
Sun, 06 Mar 2011 00:00:00 +0000
http://www.doctrine-project.org/2011/03/05/doctrine-maintenance-mar05.html http://www.doctrine-project.org/2011/03/05/doctrine-maintenance-mar05.html <![CDATA[Maintenance Releases 2.0.2 DBAL and ORM]]>

Maintenance Releases 2.0.2 DBAL and ORM

Slightly delayed but here are the releases of DBAL and ORM versions 2.0.2:

A total of 22 issues was fixed.

There was one big change in the build mechanism. Symfony YAML and Console dependencies are now converted to git submodules and are also shipped as their own PEAR packages (DoctrineSymfonyYaml and DoctrineSymfonyConsole).

]]>
Sat, 05 Mar 2011 00:00:00 +0000
http://www.doctrine-project.org/2011/02/19/doctrine-mongodb-odm-beta2-released.html http://www.doctrine-project.org/2011/02/19/doctrine-mongodb-odm-beta2-released.html <![CDATA[Doctrine MongoDB ODM BETA2 Released]]>

Doctrine MongoDB ODM BETA2 Released

After a long wait, I am happy to bring you the second beta release of the new Doctrine persistence layer for MongoDB. This release includes dozens of bug fixes and improvements and it is recommended that you upgrade as soon as possible. You can learn about how to get the code here.

About the Release

My full-time job is working at OpenSky, where we use the MongoDB ODM and many of the improvements and work are a result of the development we’ve been doing there. The changelog is very large as the development spanned almost 5 months with commits from over 15 developers all over the world. Here are some of the people who’ve contributed this release:

Documentation

Check out the documentation as it is has been completely updated and improved for this release. We fully migrated the docs to use reST and Sphinx to generate our documentation so it is much improved over the previous versions.

Doctrine Project as a Whole

The MongoDB ODM is one of a few new projects under the Doctrine umbrella. You may also want to take a look at the CouchDB ODM and the PHP Content Repository ODM. These projects are all very exciting for the Doctrine Project but more for PHP as a whole. They are a new generation of libraries built for PHP 5.3 that bring a higher level of code quality to your PHP projects.

If you encounter any problems, bugs or issues please report them in Jira. If you have any questions you can try a mailing list or IRC. Read more about the Doctrine community here.

]]>
Sat, 19 Feb 2011 00:00:00 +0000
http://www.doctrine-project.org/2011/01/30/doctrine-maintenance-jan2011.html http://www.doctrine-project.org/2011/01/30/doctrine-maintenance-jan2011.html <![CDATA[Maintenance Releases 2.0.1 of Common, DBAL and ORM]]>

Maintenance Releases 2.0.1 of Common, DBAL and ORM

We released the first maintenance versions of Common, DBAL and ORM today. See the changelogs for more information:

We also optimized the build process, so that the Version Classes in the Git Tags do not contain the “-DEV” suffix anymore.

You can get the code from Git , our PEAR channel or from the download section of the website.

]]>
Sun, 30 Jan 2011 00:00:00 +0000
http://www.doctrine-project.org/2011/01/13/roadmap-doctrine2.html http://www.doctrine-project.org/2011/01/13/roadmap-doctrine2.html <![CDATA[Whats next? Our Roadmap]]>

Whats next? Our Roadmap

Doctrine 2 is now stable for about three weeks and we are pretty happy about the increase in community discussions on IRC and mailing list. Additionally its good to see that we are not flooded with new bug reports and we can keep closing all the incoming issues very fast.

At this point you are probably interested in our roadmap for minor and bugfix releases.

  • We will release bugfix releases every other month
  • We target minor releases for every 6 month, leading with a four month implementation and then a beta + RC timespan of two month.

To be specific, 2.0.1 is scheduled for next week and 2.1 is scheduled for June 30th 2011.

You can follow the Tracker with all the features that are planned for 2.1:

http://www.doctrine-project.org/jira/browse/DDC/fixforversion/10022

You can already start testing 2.1 development with two new features as of last week:

]]>
Thu, 13 Jan 2011 00:00:00 +0000
http://www.doctrine-project.org/2010/12/21/doctrine2-released.html http://www.doctrine-project.org/2010/12/21/doctrine2-released.html <![CDATA[Doctrine 2 First Stable Release]]>

Doctrine 2 First Stable Release

We are happy to announce the immediate release of the first stable Doctrine 2.0 version. This release marks the end of 2.5 years of dedicated development starting in early 2008 and ending as a christmas present to our users. We wish everyone a merry christmas!

During the last years a core team of five people contributed large parts of the code and many developers contributed small patches and features. In the end the Doctrine 1 code was refactored beyond recognition, replacing the original ActiveRecord Doctrine 1 with a new DataMapper implementation. We want to thank all the contributors and early adopters for all the feedback and discussions.

What is new in Doctrine 2?

  • DQL is now a real language inside Doctrine, based on an EBNF that is parsed and transformed to SQL. Benefits of this refactoring are readable error messages, the generation of an AST that allows us to support many different vendors and powerful hooks for developers to modify and extend the DQL language to their needs. DQL can either be written as a string or be generated using a powerful QueryBuilder object.
  • Your persistent objects (called entities in Doctrine 2) are not required to extend an abstract base class anymore. Doctrine 2 allows you to use Plain old PHP Objects.
  • The UnitOfWork is not an alibi-pattern as implemented in Doctrine 1. It is the most central pattern in Doctrine 2. Instead of calling save() or delete() methods on your Doctrine_Record instances you now pass objects to the data mapper object called EntityManager and it keeps track of all changes until you request a synchronisation between database and the current objects in memory. This process is very efficient and has consistent semantics. This is a significant improvement over Doctrine 1 in terms of performance and developer ease-of-use.
  • There are no code-generation steps from YAML to PHP involved in the library anymore. YAML, XML, PHP and Doc-Block Annotations are four first-class citizens for defining the metadata mapping between objects and database. A powerful caching layer allows Doctrine 2 to use runtime metadata without relying on code-generation.
  • A clean architecture and powerful algorithms make Doctrine 2 magnitudes faster than Doctrine 1.
  • Doctrine 2 supports an API that allows you to transform an arbitrary SQL statements into an object-structure. This feature is used by the Doctrine Query Language itself and is a first-class citizen of the library. It essentially allows you to make use of powerful vendor-specific features and complex SQL statements without having to cirumvent the ORM completely.
  • Inheritance is not akward anymore. There are now three different types of inheritance to choose from: Mapped Superclasses, Single-Table- and Joined-Table-Inheritance.
  • Many more features, just see the reference guide on what is possible with Doctrine 2.

Why did we take so long to develop this new major release?

There are several reasons:

The refactoring of the original Doctrine 1 code marks a paradigm shift in how we approach object persistence in PHP. Making use of PHP 5.3 only features we could write an ORM whose internals are much more powerful than the first version of Doctrine. This meant rewriting lots of features from scratch and refactoring other code beyond recognition. Many features were carefully implemented and have been discussed for weeks or month in our team. We feel that not a single feature in this release can be called a hack or has negative architectural implications along the road.

As a user an ORM means committing yourself to a library that you haven’t written yourself and trust it to handle your most important code: The business and domain logic. We wanted to release a high quality library and make sure it has no bugs when it is released. This explains why the first alpha was already released over a year ago and we have been fixing every little bug that appeared for the last 14 months. When you download Doctrine 2 now we feel this code is more stable and much more maintainable than Doctrine 1. The ORM itself has about 1000 tests where half of these are functional tests that successfully run against all the supported database vendors MySQL, SQLite, PostgreSQL, Oracle and MSSQL. The database access layer and common libraries come with an additional 400 tests.

We wanted the release to ship with a complete and well-thought-out documentation. Writing such a documentation takes time. The current documentation is probably not perfect, but it contains a very detailed reference guide and a small tutorial to get started. Additionally there is a cookbook with several recipes that you can use with your Doctrine 2 project.

While Doctrine 1 had pretty powerful SQL abstraction we felt there were better libraries out there that could be incoporated into Doctrine 2. The new database abstraction layer of Doctrine 2 is much more powerful than the Doctrine 1 DBAL and is powered by code from other great libraries such as Zeta Components, Zend Framework and PEAR MDB2. On top of this it can also be used standalone, you can use the DBAL without having to use the ORM.

Dropping Features of Doctrine 1

But Doctrine 2 is not only a new version of Doctrine 1. We also dropped a lot of features that we find inappropriate for the core of an ORM library:

  • Validators have been dropped. Use a framework library like Zend or Symfony for validator support, they ship much more powerful validators than Doctrine 1 ever had. If you don’t like frameworks there is ext/filter to consider.
  • We killed the magic features: Doctrine 2 does not offer behaviors as a core feature anymore. We came to the conclusion that behaviors in the core lead to the big ball of mud called Doctrine 1. The code is nearly unmaintainable because of all the special logic and magic that works everywhere. That is why Doctrine 2 focuses on being a consistent and extensible object-relational mapper only and behaviors should be released as extensions on top of Doctrine 2. While this approach was questioned by many of the Doctrine 1 users we think this is the right approach. We are already seeing third party libraries and extensions like Doctrator based on Doctrine 2 that implement these features.
  • Explicit multiple connection support has been dropped. Use multiple instances of Doctrine\DBAL\Connection or Doctrine\ORM\EntityManager. Doctrine 2 uses no global state that could affect the usage of multiple instances.

Is Doctrine 2 backwards compatible?

No it is not. Doctrine 1 and 2 have nothing in common. For what its worth they only share the same project name. You cannot simply move from your Doctrine 1.2 to a Doctrine 2 project. Why didn’t we release a backwards compatible ORM? Because we think Doctrine 1 has architectural flaws that cannot be fixed.

What is the plan for Doctrine 2 beyond this release?

With the core that is now Doctrine 2 we plan to keep the library backwards compatible at all times. Not only for minor and mini-releases such as 2.0.1 or 2.1, even for potential releases of a Doctrine 3 or 4 version we plan to avoid public API refactorings as much as possible. If however we feel that there is overwhelming evidence that a public API refactoring makes the ORM faster and leads to more maintainable code we will not hesitate to break API for a 3.0 release.

This approach comes at costs that we are willing to pay. All new features have to pass a requirements discussion and pros/cons are carefully weighted against each other. That is also why we try to expose as little of our internals as possible. This certainly hurts extensibility of Doctrine 2, but with our expected quality level and review process we hope to bring the costs of this approach down. You should never be forced to extend Doctrine 2 just to fix bugs, which is the most important reason for extensibility in other PHP libraries.

Where do I start?

You can download Doctrine 2 from our downloads section , install it via PEAR or find it in the Github repository. Symfony 2 also ships with a current version of Doctrine 2. After you installed Doctrine 2 you can go to the documentation and start reading the reference guide or the tutorial.

If you find any bugs or have feature requests you should check our Bug-Tracker and report bugs or feature requests. If you want to discuss about Doctrine 2 you can either use the Google Group or join the #doctrine channel on the Freenode IRC Network. Also make sure to check the current Limitations and Known Issues section in the docs. We are trying to be honest about what Doctrine 2 can and can’t do but might do in the future.

]]>
Tue, 21 Dec 2010 00:00:00 +0000
http://www.doctrine-project.org/2010/12/12/doctrine2-orm-rc2-released.html http://www.doctrine-project.org/2010/12/12/doctrine2-orm-rc2-released.html <![CDATA[Doctrine DBAL RC5 and ORM RC2 released]]>

Doctrine DBAL RC5 and ORM RC2 released

We are happy to announce the immediate availability of Doctrine DBAL RC5 and Doctrine ORM RC2. There have been almost only minor bugfixes in both packages that came up in the last week.

There is one notable change in ORM: If you execute a DQL Query before RC2 a flush would be issued on the EntityManager if there were pending insertions. This flush has now been removed. It was never documented to be executed, so we don’t think this will cause major pain to anyone. Just make sure to call flush explicitly whenever you need it.

See the changelogs for both projects:

Both DBAL and ORM are essentially bug-free. All the still open bug reports are either:

  • Improvement/feature requests (only marked as bug)
  • Minor and will be fixed in 2.1, because they need some refactorings. We will make sure that they appear in the Known Issues section before the final release.
  • Some trivial bugs in Tools/Console namespace that don’t affect the core of the ORM. We are waiting for more feedback on those issues.

Expect these Release Candidates to be tagged as final if no critical or major issues are discovered in the next week.

You can grab the code from our downloads section or directly from Github.

In these last days before the final release we will focus on the documentation. As you might have noticed we already switched the ORM documentation to be rendered with Sphinx and ReStructured Text. You are now able to search the docs. We will update the layout to be more Doctrine friendly and migrate the other packages to Sphinx/ReST in the next days.

]]>
Sun, 12 Dec 2010 00:00:00 +0000
http://www.doctrine-project.org/2010/12/04/doctrine2-rc1.html http://www.doctrine-project.org/2010/12/04/doctrine2-rc1.html <![CDATA[Doctrine ORM RC1 released]]>

Doctrine ORM RC1 released

We are pleased to announce the immediate availability of the first Release Candidate of the Doctrine ORM. Over 2 years of dedicated development will soon lead to the final release. If no non-trival bugs are reported in the period of the next 1-2 weeks this release candidate will serve as basis for the final release.

For this release candidate over 70 tickets were closed. See the changelog for a detailed overview:

We want to thank everybody for their contributions and help.

]]>
Sat, 04 Dec 2010 00:00:00 +0000
http://www.doctrine-project.org/2010/11/18/doctrine2-behavioral-extensions.html http://www.doctrine-project.org/2010/11/18/doctrine2-behavioral-extensions.html <![CDATA[Doctrine2 Behavioral Extensions]]>

Doctrine2 Behavioral Extensions

These behavioral extensions will give you another view on Doctrine2 capabilities handling behaviors through the EventListeners. These extensions operate like some of the most commonly used behaviors, leaving the domain objects as clean as possible. Annotations makes it easy to understand an intended behavior of properties on your Entities.

Hi, my name is Gediminas Morkevicius, I have 4 year experience in C++ and PHP 5 and I’m very keen on new technologies and Doctrine2 is one of them. Development is not only a job for me, but it is my lifestyle and I’m pleased to give some love back to Doctrine2.

I would like to thank Doctrine2 and Symfony2 teams for these wonderful projects. They have great potential.

**NOTE** This blog entry relates to Doctrine2 Beta4 ORM version and could possibly be outdated depending on what the current version of Doctrine2 is at the time of you reading this post. Then integrating these extensions on your project it is recommended to use latest Doctrine2 library packages, because where are most recent updates used on extensions for metadata caching and annotations.

Content:

  • Introduction on behavioral extensions
  • Setup and autoloading
  • Translatable extension
  • Tree extension
  • Sluggable extension
  • Timestampable extension
  • All nested together

First of all, this post intends to give an example on how “behaviors” can be implemented through the Doctrine2 EventListeners. All these behavioral extensions can be nested and support flush operation which can include lots of update, insert and remove actions. This is the most common issue when behavior development process is started.

Furthermore, all extensions are mapped by annotations consequently leaving domain objects clean from interfaces and their methods. Plus, the performance speed is even greater if cache driver is used, because metadata for single Entity is mapped and validated only once.

Before we begin exploring the extensions, I`m glad to mention that these extensions are already available on Symfony2 Bundle ported by Christophe Coevoet.

## Setting up the autoloader and listeners

First of all, download this library from public github repository and setup the autoloading for extensions:

<?php
$classLoader = new \Doctrine\Common\ClassLoader('Gedmo', "/path/to/library/DoctrineExtensions/lib");
$classLoader->register();

Translatable behavior will need additional annotation driver for Translation Entity metadata. The example below illustrates the chain driver implementation:

<?php
$chainDriverImpl = new \Doctrine\ORM\Mapping\Driver\DriverChain();
$yourDefaultDriverImpl = new \Doctrine\ORM\Mapping\Driver\YamlDriver('/yml/mapping/files'); // only an example
$translatableDriverImpl = $doctrineOrmConfig->newDefaultAnnotationDriver(
    '/path/to/library/DoctrineExtensions/lib/Gedmo/Translatable/Entity'
);
$chainDriverImpl->addDriver($yourDefaultDriverImpl, 'Entity');
$chainDriverImpl->addDriver($translatableDriverImpl, 'Gedmo\Translatable');
$doctrineOrmConfig->setMetadataDriverImpl($chainDriverImpl);

Attaching the Event Listeners on the event manager

<?php
$evm = new \Doctrine\Common\EventManager();
// timestampable
$evm->addEventSubscriber(new \Gedmo\Timestampable\TimestampableListener());
// sluggable
$evm->addEventSubscriber(new \Gedmo\Sluggable\SluggableListener());
// tree
$evm->addEventSubscriber(new \Gedmo\Tree\TreeListener());
// translatable
$translationListener = new \Gedmo\Translatable\TranslationListener();
$translationListener->setTranslatableLocale('en_us');
// in real world app the locale should be loaded from session, example:
// Session::getInstance()->read('locale');
$evm->addEventSubscriber($translationListener);
// now this event manager should be passed to entity manager constructor

**NOTE** It is recommended to attach TranslationListener as the
last whereas sluggable extension must create a slug before
translating it.

## Translatable

Translatable behavior offers a very handy solution for translating specific record fields into different languages. Furthermore, it loads the translations automatically for the currently used locale. Locale can be set by TranslationListener during it’s initialization or later. It also leaves the possibility to force a specific locale directly on the Entity itself.

Feature list:

  • Translates all records automatically when object hydration is used
  • Supports a separate translation table for each Entity
  • There can be a default locale specified, which would force entity to leave its original translation in default locale.

Translatable annotations:

  • @gedmo:Translatable indicates that the column is translatable
  • @gedmo:TranslationEntity(class=”my”) this class annotation tells to use specified Entity to store translations
  • @gedmo:Locale or @gedmo:Language indicates that the column must not be mapped and that it may be used to override TranslationListener`s locale

Translatable Entity example:

<?php
namespace Entity;

/**
 * @Entity
 */
class Article
{
    /**
     * @Id
     * @GeneratedValue
     * @Column(type="integer")
     */
    private $id;

    /**
     * @gedmo:Translatable
     * @Column(type="string", length=128)
     */
    private $title;

    /**
     * @gedmo:Translatable
     * @Column(type="text")
     */
    private $content;

    /**
     * @gedmo:Locale
     */
    private $locale;

    public function getId()
    {
        return $this->id;
    }

    public function setTitle($title)
    {
        $this->title = $title;
    }

    public function getTitle()
    {
        return $this->title;
    }

    public function setContent($content)
    {
        $this->content = $content;
    }

    public function getContent()
    {
        return $this->content;
    }

    public function setTranslatableLocale($locale)
    {
        $this->locale = $locale;
    }
}

There is no need for any additional operations while working with Translatable Entities. All processing is done by event listener, just like in good old behaviors. Except that in Doctrine2 the code is simpler and easy to understand and you may inspect it and customize if you see any point in doing that.

Here are standard usage examples, the locale was set to “en_us” on listener:

<?php
$article = new \Entity\Article;
$article->setTitle('my title in en');
$article->setContent('my content in en');
$em->persist($article);
$em->flush();

This inserted an article and populated the translations for it in “en_us” locale. Now lets translate it into another language:

<?php
// first load the article
$article = $em->find('Entity\Article', 1 /*article id*/);
$article->setTitle('my title in de');
$article->setContent('my content in de');
$article->setTranslatableLocale('de_de'); // change locale
$em->persist($article);
$em->flush();

This updated an article and inserted the translations for it in “de_de” locale. The TranslationRepository gives some handy methods on retrieving all translations:

<?php
$em->clear(); // ensure the cache is clean
$article = $em->find('Entity\Article', 1 /*article id*/);
$repository = $em->getRepository('Gedmo\Translatable\Entity\Translation');
$translations = $repository->findTranslations($article);
/* $translations contains:
Array (
    [de_de] => Array
        (
            [title] => my title in de
            [content] => my content in de
        )

    [en_us] => Array
        (
            [title] => my title in en
            [content] => my content in en
        )
)*/
// the locale now is "en_us" and current article::title in db is "my title in de"
echo $article->getTitle();
// prints: "my title in en" because it loads the translation automatically

Using the “default locale”:

In some cases we need the default translation as a fallback if record does not have a translation on globally used locale. In that case TranslationListener uses the current value of Entity. But there is a way to specify a default locale which would force Entity to keep it``s field value on default locale. And if record has already been translated in this locale, the record will not update it``s value, only insert a new translation into translation table. You can specify the default locale on TranslationListener`s initialization:

<?php
$translationListener->setDefaultLocale('en_us');

Using a diferent Translation Entity for translation storage:

In some cases when there are thousands of records we would like to have a single table for translations of this Entity in order to increase the performance on translation loading speed. The example below will show how to specify a diferent Entity for your translations by extending the translation mapped superclass. Thanks to Christophe Coevoet for the idea on translation abstraction.

<?php
namespace Entity\Translation;

use Gedmo\Translatable\Entity\AbstractTranslation;

/**
 * @Table(name="article_translations", indexes={
 *      @index(name="article_translation_idx", columns={"locale", "entity", "foreign_key", "field"})
 * })
 * @Entity(repositoryClass="Gedmo\Translatable\Repository\TranslationRepository")
 */
class ArticleTranslation extends AbstractTranslation
{
    /**
     * All required columns are mapped through inherited superclass
     */
}

This Entity will be used instead of default Translation Entity only if we specify a class annotation @gedmo:TranslationEntity(class=”Entity”). Now lets slightly modify our Article Entity:

<?php
/**
 * @Entity
 * @gedmo:TranslationEntity(class="Entity\Translation\ArticleTranslation")
 */
class Article
{
    // ...
}

Now all translations of Article will be stored and queried from a specific table.

## Tree

Tree behavior is not a Nested Set which it was in the first version of Doctrine. This one does not require any TreeManager nor NodeWrapper and it does not support multiple roots on tree because it is meant to be simple and is implemented through the event listener. All standard Tree operations are accessible through TreeNodeRepository which is advisable to be used for Tree structured Entities. This Tree allows all traverse operations to be done on your nodes. When performance or advanced customizations becomes an issue, a more advanced implementation like nested-set by Brandon Turner might be needed.

Tree annotations:

  • @gedmo:TreeLeft identifies the column as storage of Tree left value
  • @gedmo:TreeRight identifies the column as storage of Tree right value
  • @gedmo:TreeParent this will identify this column as a ManyToOne relation of parent node

All these annotations are required for the Tree to be functional. And here is an example of a simple Tree Entity:

<?php
namespace Entity;

/**
 * use repository for handy tree functions
 * @Entity(repositoryClass="Gedmo\Tree\Repository\TreeNodeRepository")
 */
class Category
{
    /**
     * @Column(type="integer")
     * @Id
     * @GeneratedValue
     */
    private $id;

    /**
     * @Column(length=64)
     */
    private $title;

    /**
     * @gedmo:TreeLeft
     * @Column(name="lft", type="integer")
     */
    private $lft;

    /**
     * @gedmo:TreeRight
     * @Column(name="rgt", type="integer")
     */
    private $rgt;

    /**
     * @gedmo:TreeParent
     * @ManyToOne(targetEntity="Category", inversedBy="children")
     */
    private $parent;

    /**
     * @OneToMany(targetEntity="Category", mappedBy="parent")
     * @OrderBy({"lft" = "ASC"})
     */
    private $children;

    public function getId()
    {
        return $this->id;
    }

    public function setTitle($title)
    {
        $this->title = $title;
    }

    public function getTitle()
    {
        return $this->title;
    }

    public function setParent(Category $parent)
    {
        $this->parent = $parent;
    }

    public function getParent()
    {
        return $this->parent;
    }
}

Basic usage example:

<?php
$food = new Entity\Category();
$food->setTitle('Food');

$fruits = new Entity\Category();
$fruits->setTitle('Fruits');
$fruits->setParent($food);

$vegetables = new Entity\Category();
$vegetables->setTitle('Vegetables');
$vegetables->setParent($food);

$carrots = new Entity\Category();
$carrots->setTitle('Carrots');
$carrots->setParent($vegetables);

$em->persist($food);
$em->persist($fruits);
$em->persist($vegetables);
$em->persist($carrots);
$em->flush();

The result after flush will generate the tree of food chain :)

/food (1-8)
    /fruits (2-3)
    /vegetables (4-7)
        /carrots (5-6)

Using TreeNodeRepository functions:

<?php
$repo = $em->getRepository('Entity\Category');

$food = $repo->findOneByTitle('Food');
echo $repo->childCount($food);
// prints: 3
echo $repo->childCount($food, true/*direct*/);
// prints: 2
$children = $repo->children($food);
// $children contains:
// 3 nodes
$children = $repo->children($food, false, 'title');
// will sort the children by title
$carrots = $repo->findOneByTitle('Carrots');
$path = $repo->getPath($carrots);
/* $path contains:
   0 => Food
   1 => Vegetables
   2 => Carrots
*/

// verification and recovery of tree
$repo->verify();
$em->clear(); // ensures cache clean
// can return TRUE if tree is valid, or array of errors found on tree
$repo->recover();
$em->clear(); // ensures cache clean
// if tree has errors it will try to fix all tree nodes

// single node removal
$vegies = $repo->findOneByTitle('Vegitables');
$repo->removeFromTree($vegies);
// it will remove this node from tree and reparent all children

// reordering the tree
$repo->reorder(null/*reorder starting from parent*/, 'title');
$em->clear(); // ensures cache clean
// it will reorder all tree node left-right values by the title

// moving up and down the nodes, by changing their (left, right) values
$carrots = $repo->findOneByTitle('Carrots');
$repo->moveUp($carrots, 1/*by one position*/);
// carrots now should be at the top in it`s level
$repo->moveDown($carrots, true/*to bottom*/);
// carrots now should be at the bottom in it`s level

After using such Tree operations like: reorder, recover, verify it is recommended to clear the EntityManager cache since it may have cached nodes with old left and right values. This would be an issue if you plan on using nodes during the same request after mentioned operations. And if you need some custom functions on your Node repository - simply extend the TreeNodeRepository.

## Sluggable

Sluggable behavior will build the slug from annotated fields on a chosen slug field which should store the generated slug. Slugs can be unique and styled. Currently this extension does not support unique constraint on slug field in cases when there are many inserts on a single flush operation, because it cannot issue a query to ensure uniqueness. Use a simple index instead.

Sluggable annotations:

  • @gedmo:Sluggable all columns identified by this annotation will be included in a slug
  • @gedmo:Slug this column will be used to store the generated slug
<?php
namespace Entity;

/**
 * @Entity
 */
class Article
{
    /** @Id @GeneratedValue @Column(type="integer") */
    private $id;

    /**
     * @gedmo:Sluggable
     * @Column(name="title", type="string", length=64)
     */
    private $title;

    /**
     * @gedmo:Sluggable
     * @Column(name="code", type="string", length=16)
     */
    private $code;

    /**
     * @gedmo:Slug
     * @Column(name="slug", type="string", length=128, unique=true)
     */
    private $slug;

    public function getId()
    {
        return $this->id;
    }

    public function setTitle($title)
    {
        $this->title = $title;
    }

    public function getTitle()
    {
        return $this->title;
    }

    public function setCode($code)
    {
        $this->code = $code;
    }

    public function getCode()
    {
        return $this->code;
    }

    public function getSlug()
    {
        return $this->slug;
    }
}

Basic usage example:

<?php
$article = new Entity\Article();
$article->setTitle('the title');
$article->setCode('my code');
$em->persist($article);
$em->flush();

echo $article->getSlug();
// prints: the-title-my-code

### Some other configuration options:

  • updatable (optional, default=true) - true to update the slug on sluggable field changes, false - otherwise
  • unique (optional, default=true) - true if slug should be unique and if identical it will be prefixed, false - otherwise
  • separator (optional, default=”-”) - separator which will separate words in slug
  • style (optional, default=”default”) - “default” all letters will be lowercase, “camel” - first letter will be uppercase
<?php
// diferent slug configuration example
class Article
{
    // ...
    /**
     * @gedmo:Slug(style="camel", separator="_", updatable=false, unique=false)
     * @Column(name="slug", type="string", length=128, unique=true)
     */
    private $slug;
    // ...
}

// result would be: The_Title_My_Code

## Timestampable

Timestampable behavior will automate the update of date fields on your Entities. It works through annotations and can update fields on creation, update or even on specific internal or related Entity property change.

Timestampable annotations:

  • @gedmo:Timestampable this annotation specifies that this column is timestampable, by default it updates this column on general update. If column is not (date, datetime or time) it will trigger an exception. Bellow are listed available configuration options:

Available configuration options:

  • on - is the main option and can be: create, update or change. This option indicates when an update should be triggered
  • field - only valid if on=”change” is specified, tracks property for changes
  • value - only valid if on=”change” is specified, if tracked field has the specified value when it triggers an update
<?php
namespace Entity;

/**
 * @Entity
 */
class Article
{
    /** @Id @GeneratedValue @Column(type="integer") */
    private $id;

    /**
     * @Column(type="string", length=128)
     */
    private $title;

    /**
     * @var datetime $created
     *
     * @gedmo:Timestampable(on="create")
     * @Column(type="date")
     */
    private $created;

    /**
     * @var datetime $updated
     *
     * @Column(type="datetime")
     * @gedmo:Timestampable(on="update")
     */
    private $updated;

    public function getId()
    {
        return $this->id;
    }

    public function setTitle($title)
    {
        $this->title = $title;
    }

    public function getTitle()
    {
        return $this->title;
    }

    public function getCreated()
    {
        return $this->created;
    }

    public function getUpdated()
    {
        return $this->updated;
    }
}

## All nested together

<?php
namespace Entity;

/**
 * @Entity(repositoryClass="Gedmo\Tree\Repository\TreeNodeRepository")
 */
class Category
{
    /**
     * @Column(name="id", type="integer")
     * @Id
     * @GeneratedValue
     */
    private $id;

    /**
     * @gedmo:Translatable
     * @gedmo:Sluggable
     * @Column(length=64)
     */
    private $title;

    /**
     * @gedmo:TreeLeft
     * @Column(type="integer")
     */
    private $lft;

    /**
     * @gedmo:TreeRight
     * @Column(type="integer")
     */
    private $rgt;

    /**
     * @gedmo:TreeParent
     * @ManyToOne(targetEntity="Category", inversedBy="children")
     */
    private $parent;

    /**
     * @OneToMany(targetEntity="Category", mappedBy="parent")
     * @OrderBy({"lft" = "ASC"})
     */
    private $children;

    /**
     * @gedmo:Translatable
     * @gedmo:Slug(style="camel", separator="_")
     * @Column(length=128)
     */
    private $slug;

    /**
     * @gedmo:Timestampable(on="create")
     * @Column(type="date")
     */
    private $created;

    /**
     * @gedmo:Timestampable(on="update")
     * @Column(type="datetime")
     */
    private $updated;

    public function getId()
    {
        return $this->id;
    }

    public function setTitle($title)
    {
        $this->title = $title;
    }

    public function getTitle()
    {
        return $this->title;
    }

    public function setParent(Category $parent)
    {
        $this->parent = $parent;
    }

    public function getParent()
    {
        return $this->parent;
    }

    public function getCreated()
    {
        return $this->created;
    }

    public function getUpdated()
    {
        return $this->updated;
    }

    public function getSlug()
    {
        return $this->slug;
    }
}

After running some inserts you will get the expected result. Don`t be afraid to use concurrent flush with many inserts and updates or even remove operations, everything is meant to work fine.

Some of you may think that using no interface takes longer to check Entities on events. In fact, it takes only a single ‘if’ statement and a cache check on first request. This way the process is much cleaner.

Maybe these extensions will help some of you realize how clean domain objects can be and how well the model represents itself. It’s much more convenient than Active Record - browsing several extended classes, going through magic methods of those classes. While here you see everything in one grasp.

There will be updates on my blog page and new articles which may interest some of you. You can give some love back by forking a repository and creating an ODM Document support on extensions or suggesting me an idea of improvements or maybe an issue which you have detected.

]]>
Thu, 18 Nov 2010 00:00:00 +0000
http://www.doctrine-project.org/2010/11/18/common-rc2-dbal-rc2-release.html http://www.doctrine-project.org/2010/11/18/common-rc2-dbal-rc2-release.html <![CDATA[Common RC2 and DBAL RC3 released]]>

Common RC2 and DBAL RC3 released

Today we are happy to announce the second release candidate of Doctrine Common and the first, second and third release candidate (yes, all in one!) of DBAL.

In the Common package 3 bugs have been fixed, in the DBAL package 9 bugs have been fixed. See the changelogs for details:

We are especially thankful for the support Microsoft has been giving us to integrate PDO Sqlsrv. Juozas was invited to Jumpin Camp and had time to finish full support for the SQL Server.

The release of the first release candidate of the ORM package is not far away. We will be waiting some days to get some early feedback on the latest updates (updated Common and DBAL dependencies). Expect the first release candidate for someday next week.

]]>
Thu, 18 Nov 2010 00:00:00 +0000
http://www.doctrine-project.org/2010/09/01/birthday-release-party.html http://www.doctrine-project.org/2010/09/01/birthday-release-party.html <![CDATA[Birthday Release Party]]>

Birthday Release Party

Today is Jonathan’s birthday and in order to celebrate properly we’re rolling out three new releases.

Doctrine Common RC1

The first release candidate of the Doctrine Common project.

Doctrine DBAL BETA4

The last beta release of the Doctrine DBAL project.

Doctrine ORM BETA4

The last beta release of the Doctrine ORM project.

Again we want to thank everyone who participated in the ongoing development efforts, whether it was through bug reports, comments, critique, praise and/or actual code contributions.

What next

Some might know that we originally planned to release 2.0 stable today but we’re simply not there yet. However, things are going quite well and we’re confident that the final releases of the 2.0 versions are close. The ORM and DBAL now enter a final phase of bug-fixing to resolve any issues we find critical for the final releases and will then follow the Common project into RC (release candidate) status.

]]>
Wed, 01 Sep 2010 00:00:00 +0000
http://www.doctrine-project.org/2010/08/24/doctrine-orm-version-1-2-3-released.html http://www.doctrine-project.org/2010/08/24/doctrine-orm-version-1-2-3-released.html <![CDATA[Doctrine ORM Version 1.2.3 Released]]>

Doctrine ORM Version 1.2.3 Released

]]>
Tue, 24 Aug 2010 00:00:00 +0000
http://www.doctrine-project.org/2010/08/18/mongodb-odm-1-0-0beta1-released.html http://www.doctrine-project.org/2010/08/18/mongodb-odm-1-0-0beta1-released.html <![CDATA[MongoDB ODM 1.0.0BETA1 Released]]>

MongoDB ODM 1.0.0BETA1 Released

Today I am happy to tell you we have released the first beta version of the MongoDB Object Document Mapper. It contains many fixes and general improvements across the code.

We fixed lots of things reported by our users in Jira but also made lots of other improvements like improving the use of atomic operators. Read on for a complete list of the issues fixed in Jira:

Fixed Jira Issues

  • [MODM-32] - dbref $id persisted as string instead of objectid

  • [MODM-33] - Class-level annotations are ignored if set on MappedSuperclass

  • [MODM-34] - Custom Id always gets sent with changeset

  • [MODM-35] - Proxy item gets reset on persistent collection load if that item was in the collection

  • [MODM-36] - Embedded relations are not persisted after a flush()

  • [MODM-37] - Problems with EmbedMany and discrimatorMap and discriminatorField

  • [MODM-38] - Using YAML description with embedMany causes PHP notice error

  • [MODM-41] - Hydration down not work for annotation “@ReferenceMany”

  • [MODM-42] - PersistentCollection fails when working with MongoGridFs

  • [MODM-45] - Doctrine doesn’t persist empty objects

  • [MODM-46] - @AlsoLoad annotation causes exception when used together with Embed/Reference annotations

  • [MODM-47] - @AlsoLoad annotation, used on method causes fatal error

  • [MODM-48] - Embedded document changes are ignored if it was empty before

  • [MODM-49] - Getting PHP notice and warning with empty persistent collection

  • [MODM-50] - GridFs file classes don’t support inheritance

  • [MODM-43] - Explicit schema migration

  • [MODM-40] - Move value scalarization and comparison to Unit Of Work

Download

You can directly download the PEAR package file here. You can manually extract the code or you can install the PEAR package file locally.

$ pear install /path/to/DoctrineMongoDBODM-1.0.0BETA1.tgz

Checkout from github

$ git clone git://github.com/doctrine/mongodb-odm.git mongodb_odm
$ cd mongodb_odm
$ git checkout 1.0.0BETA1

Install via PEAR

$ pear install pear.doctrine-project.org/DoctrineMongoDBODM-1.0.0BETA1
]]>
Wed, 18 Aug 2010 00:00:00 +0000
http://www.doctrine-project.org/2010/08/10/mongodb-odm-atomic-operator-improvements.html http://www.doctrine-project.org/2010/08/10/mongodb-odm-atomic-operator-improvements.html <![CDATA[MongoDB ODM: Atomic Operator Improvements]]>

MongoDB ODM: Atomic Operator Improvements

Recently we’ve improved the support for use of atomic operators and how much it takes advantage of them in the Doctrine MongoDB ODM. Now when updating embedded documents it will use dot annotation to $set the individual properties instead of sending the entire document even if only one property changes.

Here is an example, first insert some new data:

<?php
$address = new Address();
$address->setStreet('6512 Mercomatic Ct');

$user = new User();
$user->setUsername('jwage');
$user->setAddress($address);
$user->addPhonenumber(new Phonenumber('6155139185'));

$dm->persist($user);
$dm->flush();

Now if we make some changes and flush() again it will perform an update:

<?php
$phonenumbers = $user->getPhonenumbers();

$address->setCity('Nashville');
$phonenumbers[0]->setPhonenumber('booooo');

$user->addPhonenumber(new Phonenumber('1234'));

$dm->flush();

The above will result in the following queries, first it must run a $set to modify existing embedded documents:

Array
(
    [$set] => Array
        (
            [address.city] => Nashville
            [phonenumbers.0.phonenumber] => booooo
        )

)

Then it issues another update to $pushAll the new phonenumbers:

Array
(
    [$pushAll] => Array
        (
            [phonenumbers] => Array
                (
                    [0] => Array
                        (
                            [phonenumber] => 1234
                        )

                )

        )

)
]]>
Tue, 10 Aug 2010 00:00:00 +0000
http://www.doctrine-project.org/2010/08/07/dc2-experimental-associations-id-fields.html http://www.doctrine-project.org/2010/08/07/dc2-experimental-associations-id-fields.html <![CDATA[Experimental Doctrine 2 Feature: Associated Entities as Id Fields]]>

Experimental Doctrine 2 Feature: Associated Entities as Id Fields

Doctrine 2 supports composite keys of primitive types from the beginning, however we realized early that a very common use-case is a composite key with one or more elements being associated entities. For example think of a CMS System which allows Article Translations. A common SQL schema for this case would be:

[sql]
CREATE TABLE article (id INT PRIMARY KEY, title VARCHAR(255), body LONGTEXT);

CREATE TABLE article_translations (article_id INT, language CHAR(3), title VARCHAR(255), body LONGTEXT, PRIMARY KEY (article_id, language));

This sort of schema cannot be mapped with Doctrine 2 currently, it would be required to add another column id on the article_translations table and enforce a unique constraint on article_id + language.

Under the umbrella of DDC-117 and some related tickets there were discussions about adding a feature that would help solve this problem: Allowing to add @Id to @ManyToOne or @OneToOne mappings. I committed this feature into an experimental Git branch today and we ask you to test this with as many crazy scenarios and use-cases as possible.

This feature can potentially be uber-powerful, however we want to be sure that it works correctly and does not have to many problematic edge-cases. Therefore we need your feedback.

Personally I want this feature in core very much, however composite keys are very tricky. We want to find as many problematic cases with this feature as possible. That would enable us to evaluate if this approach will be merged into Doctrine 2.1 or not.

NOTE

This feature currently only works with Annotations Mapping Driver. XML and YAML will follow later.

By the way, the previous example is actually one of the functional test-cases for this feature:

<?php
/**
 * @Entity
 */
class DDC117Article
{
    /** @Id @Column(type="integer") @GeneratedValue */
    private $id;
    /** @Column */
    private $title;

    /**
     * @OneToMany(targetEntity="DDC117Translation", mappedBy="article")
     */
    private $translations;

    public function __construct($title)
    {
        $this->title = $title;
        $this->translations = new \Doctrine\Common\Collections\ArrayCollection();
    }
}

/**
 * @Entity
 */
class DDC117Translation
{
    /**
     * @Id @ManyToOne(targetEntity="DDC117Article")
     */
    private $article;

    /**
     * @Id @column(type="string")
     */
    private $language;

    /**
     * @column(type="string")
     */
    private $title;

    public function __construct($article, $language, $title)
    {
        $this->article = $article;
        $this->language = $language;
        $this->title = $title;
    }
}

$article = new DDC117Article("foo");
$em->persist($article);
$em->flush();

$translation = new DDC117Translation($article, "en", "Bar");
$em->persist($translation);
$em->flush();
]]>
Sat, 07 Aug 2010 00:00:00 +0000
http://www.doctrine-project.org/2010/08/06/doctrine2-orm-beta3.html http://www.doctrine-project.org/2010/08/06/doctrine2-orm-beta3.html <![CDATA[Doctrine ORM Beta 3 released]]>

Doctrine ORM Beta 3 released

We would like to announce the immediate release of Doctrine ORM BETA 3:

We fixed 45 issues, most of them bugs reported by our users. The ORM package is now in a state where no new features will be added and we will fully concentrate the efforts on fixing bugs and bringing the release to a stable state.

Notable changes include:

  • EntityManager#merge() has been improved considerably and now also accepts new entities.
  • Uninitialized Proxies can now be serialized and only throw an exception when they are unserialized and accessed without being merged into the EntityManager.
  • New method EntityManager#getPartialReference() that returns a partial entity that only contains the entities primary key and won’t lazy-load (hence “partial”).

This release contains three backwards incompatible changes you should know about when upgrading:

Changed SQL implementation of Postgres and Oracle DateTime types

The DBAL Type “datetime” included the Timezone Offset in both Postgres and Oracle. As of this version they are now generated without Timezone (TIMESTAMP WITHOUT TIME ZONE instead of TIMESTAMP WITH TIME ZONE). See this comment to Ticket DBAL-22 for more details as well as migration issues for PostgreSQL and Oracle.

Both Postgres and Oracle will throw Exceptions during hydration of Objects with “DateTime” fields unless migration steps are taken!

Removed multi-dot/deep-path expressions in DQL

The support for implicit joins in DQL through the multi-dot/Deep Path Expressions was dropped. For example:

SELECT u FROM User u WHERE u.group.name = ?1

“u.group.name” is a nested path expression that is an implicit join. Internally the DQL parser would rewrite these queries to:

SELECT u FROM User u JOIN u.group g WHERE g.name = ?1

This explicit notation will be the only supported notation as of now. The internal handling of nested path expressions for implicit joins in the DQL Parser was too complex and error prone in edge cases and required special treatment for several features we added. Note that this does not remove any existing functionality, only a convenience notation that can be expressed otherwise. Hence the generated SQL of both notations is exactly the same.

Default Allocation Size for Sequences

The default allocation size for sequences has been changed from 10 to 1. This step was made to not cause confusion with users and also because it is partly some kind of premature optimization.

What next

It seems likely that we will not be able to hold the anticipated release date of September 1st for the final release. Instead September 1st will likely see the last beta release, BETA 4, after which we hope to enter the release candiates soon, followed by the stable release.

]]>
Fri, 06 Aug 2010 00:00:00 +0000
http://www.doctrine-project.org/2010/07/30/doctrine-mongodb-odm-1-0-0alpha2-released.html http://www.doctrine-project.org/2010/07/30/doctrine-mongodb-odm-1-0-0alpha2-released.html <![CDATA[Doctrine MongoDB ODM 1.0.0ALPHA2 Released]]>

Doctrine MongoDB ODM 1.0.0ALPHA2 Released

Today I am happy to bring you the second alpha release of the brand new Doctrine MongoDB Object Document Mapper (ODM). The release contains several bug fixes and a few enhancements. You now have the ability to mix types of documents in references and embedded documents. You can read the blog post about mixing types of documents to learn more.

Bug

  • [MODM-12] - Undefined variable error

  • [MODM-13] - Problems with merge()

  • [MODM-14] - Default database when @Document annotation does not contain a db attribute.

  • [MODM-16] - loadById failing on custom ids

  • [MODM-17] - Multiple array / object with same content/properties do not get persisted

  • [MODM-19] - Field annotation missing “name” support

  • [MODM-20] - SINGLE_COLLECTION inheritance does not work

  • [MODM-21] - AnnotationDriver doesn’t allow custom types

  • [MODM-22] - Document incorrectly scheduled for update

  • [MODM-25] - AnnotationDriver.php Line 175

  • [MODM-28] - xml mapping : embedded-document node is ignored, can’t persist

Improvement

  • [MODM-24] - Hydratation of extra fields

  • [MODM-26] - MongoCursor doesn’t implement Countable interface

Download

You can directly download the PEAR package file here. You can manually extract the code or you can install the PEAR package file locally.

$ pear install /path/to/DoctrineMongoDBODM-1.0.0ALPHA2.tgz

Or you can checkout from github:

$ git clone git://github.com/doctrine/mongodb-odm.git mongodb_odm
$ cd mongodb_odm
$ git checkout 1.0.0ALPHA2

And you can also install via PEAR:

$ pear install pear.doctrine-project.org/DoctrineMongoDBODM-1.0.0ALPHA2
]]>
Fri, 30 Jul 2010 00:00:00 +0000
http://www.doctrine-project.org/2010/07/27/document-oriented-databases-vs-relational-databases.html http://www.doctrine-project.org/2010/07/27/document-oriented-databases-vs-relational-databases.html <![CDATA[MongoDB ODM: Document-Oriented Databases vs. Relational Databases.]]>

MongoDB ODM: Document-Oriented Databases vs. Relational Databases.

My last post brought up a lot of questions on the differences between document-oriented and relational databases, possible use cases for each and approaches and gotchas one should remember when dealing with either. I had some thoughts on the subject, but they didn’t feel complete, so I decided to do some research. I started out by googling “document -oriented databases vs relational databases” , which brought a number of interesting results. After some intense reading and analyzing, I think I have a good enough understanding of the concepts, strengths and weaknesses of different data stores to write and share my findings.

Relational databases were traditionally the most obvious solution for applications that needed to store retrieve/data. With the growth of internet user-base, the number of reads and writes a typical application needed to perform grew rapidly. This led to the need for scaling. Traditional RDBMSs were hard to scale (SQL operation or Transaction spanning multiple nodes doesn’t scale well). With solutions like MySQL Cluster and Oracle RAC , this is much less of a problem now, but it wasn’t the case for a while, which led to many companies abandoning traditional RDBMSs for “noSQL” data stores.

SIDEBAR Relational Databases, Object Databases, Key-Value Stores, Document Stores, and Extensible Record Stores: A Comparison. By Rick Cattell:

The NoSQL data stores can be categorized into three groups, according to their data model and functionality:

  • Key-value Store provide a distributed index for object storage, where the objects are typically not even interpreted by the system: they are stored and handed back to the application as BLOBs, as in the popular memcached system I mentioned. However, these systems usually provide object replication for recovery, partitioning of the data over many machines, and rudimentary object persistence. Examples of key-value stores are memcached, Redis, Riak, Scalaris, and Voldemort.
  • Document Stores provide more functionality: the system does recognize the structure of the objects stored. Objects (or documents) may have a variable number of named attributes of various types (integers, strings), objects can grouped into collections, and the system provides a simple query mechanism to search collections for objects with particular attribute values. Like the key-value stores, document stores can also partition the data over many machines, replicate data for automatic recovery, and persist the data. Examples of document stores are SimpleDB, CouchDB, MongoDB, and Dynamo.
  • Extensible Record Stores, sometimes called wide column stores, provide a data model more like relational tables, but with a dynamic number of attributes, and like document stores, higher scalability and availability made possible by database partitioning and by abandoning database-wide ACID semantics. Examples of extensible records stores are BigTable, HBase, HyperTable, and Cassandra.

So when to use a document-oriented database and when to use a relational database. The former is usually much better performing and easier to scale, while doesn’t provide ACID compliance and data integrity that the later has by definition. This means that if we choose to use document-oriented database, we get more performance and scalability, but need to keep in mind, database level data integrity, transactions and locks are no longer there and will need to be embedded in the application logic itself, which will affect how we write and structure our code. In my opinion, document-oriented databases cannot replace relational databases, and vice versa. Instead, they should be used to solve different kinds of problems. At OpenSky we use both MySQL and MongoDB.

]]>
Tue, 27 Jul 2010 00:00:00 +0000
http://www.doctrine-project.org/2010/07/27/dbal2-beta3-released.html http://www.doctrine-project.org/2010/07/27/dbal2-beta3-released.html <![CDATA[Release of DBAL 2.0.0 Beta3]]>

Release of DBAL 2.0.0 Beta3

In preparation of the next ORM Beta Release in the next days we already released Doctrine DBAL 2.0.0BETA3 today. Noteworthy changes include:

  • BC Break: Changed behaviour of Postgres and Oracle DateTime now without Timezone (TIMESTAMP WITHOUT TIME ZONE instead of TIMESTAMP WITH TIME ZONE) See Ticket DBAL-22 for more details aswell as migration issues for PostgreSQL and Oracle. This will be re-announced for the ORM Beta 3 release, which is affected from this change.
  • SQL Loggers can now log execution times of queries DBAL-11
  • Several Issue with AutoIncrement Detection in Doctrine

A total of 13 issues on DBAL has been fixed.

Links:

  • Changelog

  • Installation

    NOTE DBAL BETA 3 is not currently compatible with the ORM master, we still have to make some changes. Please wait to use DBAL Beta 3 with ORM until the ORM Beta 3 is released.

]]>
Tue, 27 Jul 2010 00:00:00 +0000
http://www.doctrine-project.org/2010/07/22/mongodb-for-ecommerce.html http://www.doctrine-project.org/2010/07/22/mongodb-for-ecommerce.html <![CDATA[MongoDB ODM: MongoDB for eCommerce]]>

MongoDB ODM: MongoDB for eCommerce

Hi, my name is Bulat S. (my last name won’t make it any easier, but in case you were wondering it’s Shakirzyanov), I joined OpenSky in August 2009 (It’s been almost a year since then, but it feels like ages). My official title in the company is Hacker, which also says a lot about me (that I don’t like corporate titles for one).

The last 6 weeks were truly amazing for me. Not only was I able to learn a new technology, I also managed to contribute back to the community. But let’s go over everything step by step.

Building an eCommerce system is not easy, and building a platform is even harder. When it comes to data in eCommerce, there is nothing definite, no real structure you could stick to, and no final requirements. Something as obvious as the “item you add to cart” could be overly complicated when it comes to data.

There is a good example of how to model the database for handling variable product attributes; Magento is one of the most advanced open source eCommerce solutions available today. It uses EAV (Entity Attribute Value) , which solves the problem of variable attributes by sacrificing database level integrity and application performance. The amount of queries you need to perform to select one entity will grow with every attribute data type you introduce; however, it still is a viable solution.

A document store on the other hand lets you save two absolutely different documents in the same collection. Because of its schema-less structure it is also possible to add or remove a document’s properties after saving - it’s a database that adapts to your data structure on the fly.

At OpenSky , we decided to use MongoDB for storage of products and use relational databases for order-related data since MongoDB doesn’t support transactions.

So what is the benefit of using MongoDB over MySQL, or any other RDBMS, for storing variable attribute data. Performance. This is the pseudo-query we would have to write to select one product, with id 1, and all of its attributes in a typical EAV model:

[txt]
SELECT * FROM `product` WHERE id = 1;
SELECT * FROM `product_attributes` = WHERE product_id = 1;
SELECT * FROM `product_values_int` WHERE product_id = 1;
SELECT * FROM `product_values_varchar` WHERE product_id = 1;
SELECT * FROM `product_values_datetime` WHERE product_id = 1;
SELECT * FROM `product_values_text` WHERE product_id = 1;
SELECT * FROM `product_values_float` WHERE product_id = 1;

After the above queries are run, there would be a huge step of data hydration into the product object, which Magento handles quite well, albeit slowly. Contrast this with what we would do in MongoDB:

[javascript]
db.products.find({'_id': '1'});

Not only is the selection simpler, but it also returns a JSON object, which can easily be hydrated into a native PHP object. And here is how a configurable product could be represented in MongoDB:

[javascript]
{
    "_id": ObjectId("4bffd798fdc2120019040000")
    "name": "Configurable T-Shirt"
    "options": [
        {
            "name": "small",
            "price": 12.99
        },
        {
            "name": "medium",
            "price": 15.99
        },
        {
            "name": "large",
            "price": 17.99
        }
    ]
}

**NOTE** There is no need for joins, as product options are a
collection of embedded objects. Object references (akin foreign key
relationships in RDBMSs) are also possible, but they are generally
only necessary if you need to access the object independently. For
instance, if I needed a page to list all product options across all
products, I would probably put options into their own collection
and reference them from the product document.

Of course, there are plenty of ORM libraries for MongoDB , which were either hard-to-extract parts of frameworks, not quite ORMs or used the ActiveRecord pattern (which after using DataMapper for quite some time, I wouldn’t want to go back to). The very same day I started writing an object document mapper (ODM) to use at OpenSky , Jon Wage (developer for the Doctrine project) released a proof-of-concept MongoDB ODM , which you can find on github. After contacting Jon and giving his library a couple of tries and tests , I decided to use it for OpenSky‘s products domain layer.

I started to submit patches and unit tests to the project and soon joined the core team for MongoDB ODM. Today, we are past first alpha release of the project, and this is my first post on the Doctrine blog (yay!).

Getting back to our example, this is how the product and embedded option classes for the aforementioned data structure could look:

<?php
// Product.php
/**
 * @Document(collection="products")
 */
class Product
{

    /**
     * @Id
     */
    private $id;

    /**
     * @String
     */
    private $name;

    /**
     * @EmbedMany(targetDocument="Product\Option")
     */
    private $options = array();

    public function getId()
    {
        return $this->id;
    }

    public function setName($name)
    {
        $this->name = $name;
    }

    public function getName()
    {
        return $this->name;
    }

    public function addOption(Product\Option $option)
    {
        $this->options[] = $option
    }

    //...
}

And the Product class:

<?php
// Product/Option.php
namespace Product;
/**
 * @EmbeddedDocument
 */
class Option
{

    /**
     * @String
     */
    private $name;

    /**
     * @Float
     */
    private $price;

    public function setName($name)
    {
        $this->name = $name;
    }

    public function getName()
    {
        return $this->name;
    }

    public function setPrice($price)
    {
        $this->price = $price;
    }

    public function getPrice()
    {
        return $this->price;
    }

    //...
}

Using the DocumentManager instance, we could easily persist the product with:

<?php
$product = new Product();
$product->setName('Configurable T-Shirt');

$small = new Product\Option();
$small->setName('small');
$small->setPrice(12.99);
$product->addOption($small);

$medium = new Product\Option();
$medium->setName('medium');
$medium->setPrice(15.99);
$product->addOption($medium);

$large = new Product\Option();
$large->setName('large');
$large->setPrice(15.99);
$product->addOption($large);

$documentManager->persist($product);
$documentManager->flush();

**NOTE** MongoDB ODM intelligently uses
`atomic operators <http://www.mongodb.org/display/DOCS/Atomic+Operations>`_
to update data, which makes it really fast. It also supports
inheritance (collection-per-class and single-collection
inheritances), which is similar to table inheritance design
patterns for ORMs. Check out the official Mongo ODM
`project documentation <http://www.doctrine-project.org/projects/mongodb_odm/1.0/docs/en>`_
for more information and examples. Complete instructions on how to
setup your DocumentManager instance
`can be found here <http://www.doctrine-project.org/projects/mongodb_odm/1.0/docs/reference/introduction/en>`_.

The above code would store the product object as a document in MongoDB.

There is much more to talk about in terms or technologies, techniques and practices we adopt and use at OpenSky , so this post is definitely not the last one.

]]>
Thu, 22 Jul 2010 00:00:00 +0000
http://www.doctrine-project.org/2010/07/21/mongodb-odm-query-builder-api.html http://www.doctrine-project.org/2010/07/21/mongodb-odm-query-builder-api.html <![CDATA[MongoDB ODM: Query Builder API]]>

MongoDB ODM: Query Builder API

The Doctrine MongoDB Object Document Mapper includes a fluent object oriented API for building queries to execute against MongoDB. Recently some changes were made to the API to simplify it and make it more readable. This blog post aims to demonstrate and introduce the new API to you!

Query Types

The API still supports all the types of queries you would expect:

Continue reading to see examples for each of the above types of queries!

## Find

You can easily find documents by just creating a new Query object with the createQuery() method. A new Query object defaults to a find query so you just need to pass the name of the document to query for:

<?php
$q = $dm->createQuery('User');

You can change the document being queried for by using the find() method:

<?php
$q->find('Project');

Conditions

You can limit the returned documents by specifying some conditions:

<?php
$q->field('title')->equals('The Doctrine Project');

Maybe you want to only return projects created after today:

<?php
$q->field('createdAt')->greaterThan(new MongoDate(time()));

You can even a condition on an embedded document:

<?php
$q->field('profile.firstName')->equals('Jonathan');

Also, you can add a condition for a referenced document to filter by id:

<?php
$q->field('account.$id')->equals($accountId);

The field() method specifies the current field to add the conditions to. You can optionally use the magical __call() feature of the Query object to specify the current field as well:

<?php
$q->createdAt()->greaterThan(new MongoDate(time()));

All the methods you’d expect can be used in combination with the field() method for adding conditions to your query:

  • equal($value)
  • where($javascript)
  • not($value)
  • in($values)
  • notIn($values)
  • notEqual($value)
  • greaterThan($value)
  • greaterThanOrEq($value)
  • lessThan($value)
  • lessThanOrEq($value)
  • range($start, $end)
  • size($size)
  • exists($bool)
  • type($type)
  • all($values)
  • mod($mod)

## Insert

You can easily insert new documents using the Query API as well. Just use the insert() method in combination with field() and set():

<?php
$q = $dm->createQuery('User')
    ->insert()
    ->field('username')->set('jwage')
    ->field('password')->set('password');

If you want to set the new document to insert you can use the setNewObj() method:

<?php
$q = $dm->createQuery('User')
    ->insert()
    ->setNewObj(array(
        'username' => 'jwage',
        'password' => 'password'
    ));

## Update

If you want to update a document you can use the update() method in combination with field(), set() and conditions. Here is an example where we create a query to update a user with the username jwage and give him a new password:

<?php
$q = $dm->createQuery('User')
    ->update()
    ->field('password')->set('newpassword')
    ->field('username')->equals('jwage');

## Delete

You can delete documents as well by using the delete() method in combination with conditions. Here is an example where we create a query to delete the user document with a username of jwage:

<?php
$q = $dm->createQuery('User')
    ->delete()
    ->field('username')->equals('jwage');

As you can see the fluent API makes it a bit easier to express queries that are easy to read in the same way you would read english from left to right. We hope to enhance and improve this API even more before we release the stable 1.0 version.

You can read more about the Query Builder API in the documentation.

]]>
Wed, 21 Jul 2010 00:00:00 +0000
http://www.doctrine-project.org/2010/07/20/mixing-types-of-documents.html http://www.doctrine-project.org/2010/07/20/mixing-types-of-documents.html <![CDATA[MongoDB ODM: Mixing Types of Documents]]>

MongoDB ODM: Mixing Types of Documents

One major advantage to using something like MongoDB is the fact that it is schema-less. We can store multiple types of documents in a single collection and we are not limited to a single type of document in embedded and referenced documents. This article shows how you can easily mix types of documents in collections, embedded and referenced documents.

Mixing Types in Collections

If you don’t want to use SINGLE_COLLECTION inheritance you can easily store different documents in the same collection by using a discriminator field. First define an Article document that maps to my_documents:

<?php
/**
 * @Document(collection="my_documents")
 * @DiscriminatorField(fieldName="type")
 * @DiscriminatorMap({"article"="Article", "album"="Album"})
 */
class Article
{
    // ...
}

Next create another document named Album and also map it to my_documents:

<?php
/**
 * @Document(collection="my_documents")
 * @DiscriminatorField(fieldName="type")
 * @DiscriminatorMap({"article"="Article", "album"="Album"})
 */
class Album
{
    // ...
}

Now if you create some instances and persist them they will all be stored in the my_documents collection and will have a discriminator field named type automatically set with the value specified in the mapping:

<?php
$article = new Article();
$article->setTitle('Sample Article');
// ...

$album = new Album();
$album->setName('My Album');

$dm->persist($article);
$dm->persist($album);

Finally, if you retrieve the documents they’ll all be retrieved from my_documents but you will get back the proper PHP classes that created them:

<?php
$articles = $dm->find('Article');
$albums = $dm->find('Album');

You can retrieve more then just one document type by specifying an array:

<?php
$documents = $dm
    ->createQuery(array('Article', 'Album'))
    ->execute();

The returned documents will contain instances of articles and albums!

Mixing Types in Embedded Documents

You can store multiple types of documents in embedded documents by simply omitting the targetDocument option. First create a User document and embed multiple task documents:

<?php
/** @Document(collection="users") */
class User
{
    // ...

    /** @Embedded */
    private $tasks = array();

    // ...
}

**NOTE** Notice how on the ``$tasks`` annotation we don't specify
whether it is ``one`` or ``many``. This is because we know it is
``many`` due to the default value being an array.

Now create the different types of tasks we can add to the user:

<?php
/** @EmbeddedDocument */
class DownloadTask
{
    // ...
}

/** @EmbeddedDocument */
class UploadTask
{
    // ...
}

Now you can embed any type of class in the $tasks property:

<?php
$user = $dm->findOne('User', array(...));

$task = new DownloadTask();
// ...

$user->addTask($task);

$task = new UploadTask();
// ...

$user->addTask($task);

$dm->flush();

Mixing Types in Referenced Documents

Mixing types in referenced documents works just the same as embedded by omitting the targetDocument option. In this example a user can add references to all his favorite albums, songs and books. First define a User document with a many references property for storing the users favorites:

<?php
/** @Document(collection="users") */
class User
{
    // ...

    /** @Reference */
    private $favorites = array();

    // ...
}

Now here is what the referenced documents would look like:

<?php
/** @Document(collection="albums") */
class Album
{
    // ...
}

/** @Document(collection="songs") */
class Song
{
    // ...
}

/** @Document(collection="books") */
class Book
{
    // ...
}

Now it is easy to add the references to his favorites:

<?php
$user->addFavorite($album);
$user->addFavorite($song);
$user->addFavorite($book);

$dm->flush();

When you retrieve the user and access the $favorites the documents will be grouped by type and loaded with one or more $in queries:

<?php
$user = $dm->findOne('User', array(...));
$favorites = $user->getFavorites();

// Lazily loads references
// Contains Album, Song and Book instances
foreach ($favorites as $favorite) {
    // ...
}

That is it! It is easy to take advantage of the schema-less features of MongoDB with the Doctrine Object Document Mapper (ODM)!

]]>
Tue, 20 Jul 2010 00:00:00 +0000
http://www.doctrine-project.org/2010/07/19/your-own-orm-doctrine2.html http://www.doctrine-project.org/2010/07/19/your-own-orm-doctrine2.html <![CDATA[Write your own ORM on top of Doctrine2]]>

Write your own ORM on top of Doctrine2

NOTE

The Doctrine ActiveEntity Extension is just an experiment, nothing that will be developed much further from the Doctrine Dev Team. It is only a show-case for what is possible with Doctrine2. Please feel free to take the code and develop it further.

Did you feel the urge to write your own Object-Relational Mapper after reading Martin Fowlers PoEAA? I am guilty to have tried implementing two different ORMs on my own, both now safely dumped into the trash.

In isolation each ORM pattern is easy to describe, understand and even implement. However the combination of a large set of patterns into a single implementation introduces a lot of hard to solve complexity in your code. Even simple Object-Relational-Mappers require a lot of patterns to become useful: Metadata Mapping, Identity Map, Foreign Key Mapping, Association Table Mapping and Query Object. Implementations with more features at least need the UnitOfWork and probably many more, for example handling inheritance, locking, value objects and such.

Doctrine2 already solves a lot of the head aching problems in a consistent approach. We have been working on this project for almost 2 years now, with all the experience we gained implementing Doctrine 1. Additionally we make use of well-understood concepts from other ORM implementations across various languages.

We as developers think that Doctrine2 responsibilities are very well separated such that you can exchange larger parts of the Doctrine2 core without having to re-implement everything. So if you ever feel inspired to implement your own ORM, we would be happy to offer you Doctrine2 as a foundation to build upon.

There are examples of other ORMs that have taken the re-use instead of re-implement road. For example the Groovy Grails ORM is an ActiveRecord implementation on top of the popular Hibernate Java ORM. Since Groovy is a java-virtual-machine language it can safely use the Hibernate ORM as a dependent library.

This article will describe some possible extensions and show where you can hook into the Doctrine2 core to implement your own ORM. The article will be very code focused and also comes with a Github project where all the code and some tests are hosted.

Doctrine2 and ActiveRecord

Doctrine2 is implementing the DataMapper pattern, however many programmers think ActiveRecord is better for various reasons. For me data-mappers are superiour to ActiveRecord, however I do understand why ActiveRecord is so popular: Its very easy to get started and do cool stuff with it! If you want Doctrine2 to be ActiveRecord you can have it. Actually it is very easy to turn it into a powerful ActiveRecord implementation, keeping all the powerful features such as DQL.

Some while ago Jonathan already released his approach, called the “ActiveEntity” extension. Its a single abstract php class that your entities have to implement, the code is still in our SVN repository. However a more recent version of this code is available as a project on Github. I won’t support this experiment any further, I hope somebody picks it up and starts maintaining it.

With Jonathans old code, to allow active record entities, you have to bootstrap the ActiveEntity by passing a static EntityManager:

<?php
\DoctrineExtensions\ActiveEntity::setEntityManager($em);

Now say we have a User Entity (using Jonathans old ActiveEntity):

<?php
namespace Entities;

use DoctrineExtensions\ActiveEntity;

/** @Entity */
class User extends ActiveEntity
{
    /** @Id @GeneratedValue @column(type="integer") */
    private $id;

    /** @Column(type="string") */
    private $name;
}

With PHP 5.3 late-static binding functionality we can now access the EntityRepository, a finder object for entities using a Ruby on Rails’ish notation:

<?php
$user = User::find($id);
$users = User::findBy(array("name" => "beberlei"));
$beberlei = User::findOneBy(array("name" => "beberlei"));

The code to allow this functionality is very simple:

<?php
public static function __callStatic($method, $arguments)
{
    return call_user_func_array(array(self::$_em->getRepository(get_called_class()), $method), $arguments);
}

There are also some additional methods on the ActiveEntity class that use magic **get and**set and __call methods to access the private properties of an Entity (such as the User id and name shown above). Additionally you can call save() or remove() on any instance.

For starters this offers a great ActiveRecord implementation with all the powerful features that Doctrine2 offers, such as DQL and UnitOfWork. However we can still go much further:

  • Eliminate the need to define ActiveEntity properties by metadata mapping inference
  • Adding your own powerful Metadata Mapping Layer
  • Add a Doctrine 1.2 behaviour system using the PHP 5.3.99DEV Traits functionalitiy
  • Add validation to properties of an ActiveEntity

Lets begin with a simple introduction to the Doctrine Metadata Model to explain how this is all possible.

Doctrine2 Metadata Model

You probably already saw that Doctrine2 offers many different metadata configuration mechanisms: Annotations, YAML, XML and plain PHP. Any one of this implementations will transform into an instance of Doctrine\ORM\ClassMetadata which is then cached for subsequent web requests. The ClassMetadataFactory is responsible for creating and managing those metadata instances.

Doctrine2 uses the ClassMetadata instance internally for all runtime access to your entities metadata, which means that you have to extend this class such that it works exactly the same from the outside.

If you wanted to extend the inner workings of Doctrine2, this is indeed the way to go. First extend the EntityManager to replace the ClassMetadataFactory used. This piece of code is the only hackish workaround, everything else is rather nice :-)

<?php
namespace DoctrineExtensions\ActiveEntity;

use DoctrineExtensions\ActiveEntity\Mapping\ClassMetadataFactory;

class ActiveEntityManager extends \Doctrine\ORM\EntityManager
{
    protected function __construct(Connection $conn, Configuration $config, EventManager $eventManager)
    {
        parent::__construct($conn, $config, $eventManager);

        $metadataFactory = new ActiveClassMetadataFactory($this);
        $metadataFactory->setCacheDriver($this->getConfiguration()->getMetadataCacheImpl());

        // now this is the only hack required to get it work:
        $reflProperty = new \ReflectionProperty('Doctrine\ORM\EntityManager', 'metadataFactory');
        $reflProperty->setAccessible(true);
        $reflProperty->setValue($this, $metadataFactory);
    }

    public static function create($conn, Configuration $config, EventManager $eventManager = null)
    {
        // ... copy paste from EntityManager::create()

        return new ActiveEntityManager($conn, $config, $conn->getEventManager());
    }
}

And both the ClassMetadataFactory and ClassMetadata:

<?php
namespace DoctrineExtensions\ActiveEntity\Mapping;

class ActiveClassMetadataFactory extends \Doctrine\ORM\Mapping\ClassMetadataFactory
{
    protected function _newClassMetadataInstance($className)
    {
        return new ActiveClassMetadata($className);
    }
}

class ActiveClassMetadata extends \Doctrine\ORM\Mapping\ClassMetadata
{
}

This is the foundation of your own Doctrine2-based ORM. We will see in the next section how we can use this.

Exchange Doctrine2 Reflection for Array-based Field Storage

Doctrine2 uses reflection to access the current values of an entity. This is necessary, because Doctrine2 is a Data Mapper that enforces clean separation between entities and persistence. If we extend it to be an ActiveRecord implementation this separation is not wanted anymore and we can opt for a new approach, using the get()/set() methods on our ActiveEntities.

Defining the properties “id” and “name” will then not be necessary anymore, they will all be saved in an array hash-map called “_data” inside the ActiveEntity. We cannot use annotations for metadata anymore, however the XML or YAML drivers would still work smoothly.

To get started we have to modify our ActiveClassMetadata a bit to exchange the contents of reflClass and reflFields with our own classes. Looking at the ClassMetadata code and doing some project wide searches I found out about all the necessary changes. To replace the ReflectionClass we only need to exchange getProperty and keep the rest. To exchange ReflectionProperty we only have to overwrite setAccessible(), getValue() and setValue().

<?php
namespace DoctrineExtensions\ActiveEntity\Reflection;

class ActiveEntityReflectionClass extends \ReflectionClass
{
    public function getProperty($name)
    {
        return new ActiveEntityPropertyReflection($this->name, $name);
    }
}

class ActiveEntityReflectionProperty
{
    public $name = null;
    public $class = null;

    public function __construct($class, $name)
    {
        $this->class = $class;
        $this->name = $name;
    }

    public function setAccessible($flag) {}

    public function setValue($entity = null, $value = null)
    {
        $entity->set($this->name, $value);
    }

    public function getValue($entity = null)
    {
        return $entity->get($this->name);
    }
}

This is about enough to exchange reflection transformation against a simple ActiveRecord get/set approach. Now we need to replace the all the instantiations of ReflectionClass relevant for runtime mapping with our implementation:

<?php
namespace DoctrineExtensions\ActiveEntity\Mapping;

use DoctrineExtensions\ActiveEntity\Reflection\ActiveEntityReflectionClass;
use DoctrineExtensions\ActiveEntity\Reflection\ActiveEntityReflectionProperty;

class ActiveClassMetadata extends \Doctrine\ORM\Mapping\ClassMetadata
{
    public function __construct($entityName)
    {
        parent::__construct($entityName);
        $this->reflClass = new ActiveEntityReflectionClass($entityName);
        $this->namespace = $this->reflClass->getNamespaceName();
        $this->table['name'] = $this->reflClass->getShortName();
    }

    /**
     * Restores some state that can not be serialized/unserialized.
     *
     * @return void
     */
    public function __wakeup()
    {
        // lots of code here, see the Github Repository
    }
}

Again, this is enough and our ActiveEntity Mapping now works. We can heavily modify the ActiveEntity now to loose the requirement to specify properties for the defined metadata. We can rewrite the User entity to be:

<?php
namespace Entities;

use DoctrineExtensions\ActiveEntity\ActiveEntity;

class User extends ActiveEntity
{
}

Using an XML or YAML Mapping is already enough for this ActiveEntity to work out of the box.

Implementing your own Metadata Mapping Driver

In the spirit of Doctrine 1.* or GORM there should be a PHP based metadata mapping driver now and actually Doctrine2 ships with one already:

<?php
$config = new \Doctrine\ORM\Configuration();
$config->setMetadataDriverImpl(new \Doctrine\ORM\Mapping\Driver\StaticPHPDriver());
// ...

This allows to specify the metadata within the User class:

<?php
namespace Entities;

use DoctrineExtensions\ActiveEntity\ActiveEntity;
use DoctrineExtensions\ActiveEntity\Mapping\ActiveClassMetadata;

class User extends ActiveEntity
{
    static public function loadMetadata(ActiveClassMetadata $cm)
    {
        // work with $cm here!
    }
}

You could extend that Static PHP Driver even more for the next section. We could add additional metadata information, such as names of behaviours to extend or validators or anything else.

Using Traits for Behaviours

We want to add a simple “Timestampable” behaviour now, hooking into the loadClassMetadata event as described in the documentation:

Now this is untested code, as i don’t have a PHP-5.3.99-DEV version compiled at this machine.

The following trait can be used by our User entity:

<?php
namespace DoctrineExtensions\ActiveEntity\Behaviour;

trait Timestampable
{
    public function created()
    {
        return $this->get('created');
    }

    public function updated()
    {
        return $this->get('updated');
    }

    /** will be a prePersist lifecycle hook */
    public function setCreated()
    {
        return $this->set('created', new \DateTime("now"));
    }

    /** will be a preUpdate lifecycle hook */
    public function setUpdated()
    {
        return $this->set('updated', new \DateTime("now"));
    }
}

class User extends ActiveEntity use Timestampable
{

}

We now need an Event that modifies the ActiveClassMetadata as required:

<?php
namespace DoctrineExtensions\ActiveEntity\Behaviour;

use Doctrine\ORM\Event\LoadClassMetadataEventArgs;

class TimestampableEvent
{
    public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs)
    {
        $classMetadata = $eventArgs->getClassMetadata();
        $traits = $classMetadata->reflClass->getTraitNames();
        if (!in_array("DoctrineExtensions\ActiveEntity\Behaviour\Timestampable", $traits)) {
            return;
        }

        $classMetadata->mapField(array(
            'type' => 'datetime',
            'fieldName' => 'created',
        ));
        $classMetadata->mapField(array(
            'type' => 'datetime',
            'fieldName' => 'updated',
        ));
        $classMetadata->addLifecycleCallback("prePersist", "setCreated");
        $classMetadata->addLifecycleCallback("prePersist", "setUpdated");
        $classMetadata->addLifecycleCallback("preUpdate", "setUpdated");
    }
}

You can now register this behaviour with your Entity Manager and just the usage of the trait Timestampable adds two additional fields and updates them accordingly.

NOTE

Again, the trait code is untested. It should work, but I cannot guarantee! :)

Conclusion

What are you waiting for? This article showed a very deep modification of the Doctrine2 core to turn it into Active Record. The changes required some understanding of the inner workings of Doctrine2, however not many changes were required in the end.

See the code on GitHub!

]]>
Mon, 19 Jul 2010 00:00:00 +0000
http://www.doctrine-project.org/2010/07/12/doctrine2-large-collections.html http://www.doctrine-project.org/2010/07/12/doctrine2-large-collections.html <![CDATA[Working with Large Collections in Doctrine2]]>

Working with Large Collections in Doctrine2

If you access a collection of Entity A pointing to Entity B, Doctrine2 always initializes the complete collection for you. For small collections up to around 100 entities this won’t be a problem, however as soon as collections get (much) bigger than this you can get into serious trouble.

By default Doctrine2 can only optimize adding new entities to a collection for you. This operation does not initialize the collection. This will only get you bigger collections though, reading them is still a pain.

We already got requests from several development teams for better functionality in this regard and we are planning to add a solution to this problem that is not constraining your domain model with technical blurp. However this solution is currently on our schedule for the 2.1 release of Doctrine only.

Until then I wrote a very little extension for Doctrine2 that allows you to work with large collections. It has two methods that compute the following data for any given PersistentCollection:

  • Total Number of Elements in the Collection
  • A slice of entities from the collection using a sql limit (or alternative)

You can get this extension from the DoctrineExtensions Github repository.

Working with a LargeCollection

The LargeCollection class is a handler to work with large PersistentCollections. You can instantiate it by passing an EntityManager instance:

<?php
use DoctrineExtensions\LargeCollections\LargeCollection;

$lc = new LargeCollection($em);

**NOTE**

LargeCollection only works with instances of
``PersistentCollection``, not with other implementations of the
``Doctrine\Common\Collections\Collection`` interface. That means
that you can only pass collections to it, whose owning entities
have been persisted before or are retrieved from the
EntityManager.

You can compute the total number of elements in a given collection by passing it to the count method:

<?php
$size = $lc->count($article->getComments());

You can retrieve a slice of entities from the collection by calling:

<?php
$slice = $lc->getSliceQuery($article->getComments(), $limit = 30);

As you can see this is very simple to use, but also missing some bits:

  • In your domain models you sometimes don’t want to return the Collections instance but call toArray() to encapsulate the Collections API inside the Entity. For this two new methods are required to access to the persistent collections from the inside of an entity.
  • The remove, removeElement, contains and containsKey methods could also be added to the large collection handler, making direct calls to the underlying UnitOfWork API.
  • A method that returns an IterableResult for any given collection. This would allow to iterate the complete collection on a row-by-row basis, which would eliminate possible max memory problems compared to the complete hydration of a collection.
  • Methods link()/unlink() like described in DDC-128

I hope I got your attention and maybe someone has an interest in extending the LargeCollection a little bit more.

]]>
Mon, 12 Jul 2010 00:00:00 +0000
http://www.doctrine-project.org/2010/07/07/implementing-aggregate-fields.html http://www.doctrine-project.org/2010/07/07/implementing-aggregate-fields.html <![CDATA[Implementing Aggregate Fields with Doctrine 2]]>

Implementing Aggregate Fields with Doctrine 2

You will often come across the requirement to display aggregate values of data that can be computed by using the MIN, MAX, COUNT or SUM SQL functions. For any ORM this is a tricky issue traditionally. Doctrine 2 offers several ways to get access to these values and this article will describe all of them from different perspectives.

You will see that aggregate fields can become very explicit features in your domain model and how this potentially complex business rules can be easily tested.

An example model

Say you want to model a bank account and all their entries. Entries into the account can either be of positive or negative money values. Each account has a credit limit and the account is never allowed to have a balance below that value.

For simplicity we live in a world were money is composed of integers only. Also we omit the receiver/sender name, stated reason for transfer and the execution date. These all would have to be added on the Entry object.

Our entities look like:

<?php
namespace Bank\Entities;

/**
 * @Entity
 */
class Account
{
    /** @Id @GeneratedValue @Column(type="integer") */
    private $id;

    /** @Column(type="string", unique=true) */
    private $no;

    /**
     * @OneToMany(targetEntity="Entry", mappedBy="entries", cascade={"persist"})
     */
    private $entries;

    /**
     * @Column(type="integer")
     */
    private $maxCredit = 0;

    public function __construct($no, $maxCredit = 0)
    {
        $this->no = $no;
        $this->maxCredit = $maxCredit;
        $this->entries = new \Doctrine\Common\Collections\ArrayCollection();
    }
}

/**
 * @Entity
 */
class Entry
{
    /** @Id @GeneratedValue @Column(type="integer") */
    private $id;

    /**
     * @ManyToOne(targetEntity="Account", inversedBy="entries")
     */
    private $account;

    /**
     * @Column(type="integer")
     */
    private $amount;

    public function __construct($account, $amount)
    {
        $this->account = $account;
        $this->amount = $amount;
        // more stuff here, from/to whom, stated reason, execution date and such
    }

    public function getAmount()
    {
        return $this->amount;
    }
}

Using DQL

The Doctrine Query Language allows you to select for aggregate values computed from fields of your Domain Model. You can select the current balance of your account by calling:

<?php
$dql = "SELECT SUM(e.amount) AS balance FROM Bank\Entities\Entry e " .
       "WHERE e.account = ?1";
$balance = $em->createQuery($dql)
              ->setParameter(1, $myAccountId)
              ->getSingleScalarResult();

The $em variable in this (and forthcoming) example holds the Doctrine EntityManager. We create a query for the SUM of all amounts (negative amounts are withdraws) and retrieve them as a single scalar result, essentially return only the first column of the first row.

This approach is simple and powerful, however it has a serious drawback. We have to execute a specific query for the balance whenever we need it.

To implement a powerful domain model we would rather have access to the balance from our Account entity during all times (even if the Account was not persisted in the database before!).

Also an additional requirement is the max credit per Account rule.

We cannot reliably enforce this rule in our Account entity with the DQL retrieval of the balance. There are many different ways to retrieve accounts. We cannot guarantee that we can execute the aggregation query for all these use-cases, let alone that a userland programmer checks this balance against newly added entries.

Using your Domain Model

Account and all the Entry instances are connected through a collection, which means we can compute this value at runtime:

<?php
class Account
{
    // .. previous code
    public function getBalance()
    {
        $balance = 0;
        foreach ($this->entries AS $entry) {
            $balance += $entry->getAmount();
        }
        return $balance;
    }
}

Now we can always call Account::getBalance() to access the current account balance.

To enforce the max credit rule we have to implement the “Aggregate Root” pattern as described in Eric Evans book on Domain Driven Design. Described with one sentence, an aggregate root controls the instance creation, access and manipulation of its children.

In our case we want to enforce that new entries can only added to the Account by using a designated method. The Account is the aggregate root of this relation. We can also enforce the correctness of the bi-directional Account <-> Entry relation with this method:

<?php
class Account
{
    public function addEntry($amount)
    {
        $this->assertAcceptEntryAllowed($amount);

        $e = new Entry($this, $amount);
        $this->entries[] = $e;
        return $e;
    }
}

Now look at the following test-code for our entities:

<?php
class AccountTest extends \PHPUnit_Framework_TestCase
{
    public function testAddEntry()
    {
        $account = new Account("123456", $maxCredit = 200);
        $this->assertEquals(0, $account->getBalance());

        $account->addEntry(500);
        $this->assertEquals(500, $account->getBalance());

        $account->addEntry(-700);
        $this->assertEquals(-200, $account->getBalance());
    }

    public function testExceedMaxLimit()
    {
        $account = new Account("123456", $maxCredit = 200);

        $this->setExpectedException("Exception");
        $account->addEntry(-1000);
    }
}

To enforce our rule we can now implement the assertion in Account::addEntry:

<?php
class Account
{
    private function assertAcceptEntryAllowed($amount)
    {
        $futureBalance = $this->getBalance() + $amount;
        $allowedMinimalBalance = ($this->maxCredit * -1);
        if ($futureBalance < $allowedMinimalBalance) {
            throw new Exception("Credit Limit exceeded, entry is not allowed!");
        }
    }
}

We haven’t talked to the entity manager for persistence of our account example before. You can call EntityManager::persist($account) and then EntityManager::flush() at any point to save the account to the database. All the nested Entry objects are automatically flushed to the database also.

<?php
$account = new Account("123456", 200);
$account->addEntry(500);
$account->addEntry(-200);
$em->persist($account);
$em->flush();

The current implementation has a considerable drawback. To get the balance, we have to initialize the complete Account::$entries collection, possibly a very large one. This can considerably hurt the performance of your application.

Using an Aggregate Field

To overcome the previously mentioned issue (initializing the whole entries collection) we want to add an aggregate field called “balance” on the Account and adjust the code in Account::getBalance() and Account:addEntry():

<?php
class Account
{
    /**
     * @Column(type="integer")
     */
    private $balance = 0;

    public function getBalance()
    {
        return $this->balance;
    }

    public function addEntry($amount)
    {
        $this->assertAcceptEntryAllowed($amount);

        $e = new Entry($this, $amount);
        $this->entries[] = $e;
        $this->balance += $amount;
        return $e;
    }
}

This is a very simple change, but all the tests still pass. Our account entities return the correct balance. Now calling the Account::getBalance() method will not occour the overhead of loading all entries anymore. Adding a new Entry to the Account::$entities will also not initialize the collection internally.

Adding a new entry is therefore very performant and explictly hooked into the domain model. It will only update the account with the current balance and insert the new entry into the database.

Tackling Race Conditions with Aggregate Fields

Whenever you denormalize your database schema race-conditions can potentially lead to inconsistent state. See this example:

<?php
// The Account $accId has a balance of 0 and a max credit limit of 200:
// request 1 account
$account1 = $em->find('Bank\Entities\Account', $accId);

// request 2 account
$account2 = $em->find('Bank\Entities\Account', $accId);

$account1->addEntry(-200);
$account2->addEntry(-200);

// now request 1 and 2 both flush the changes.

The aggregate field Account::$balance is now -200, however the SUM over all entries amounts yields -400. A violation of our max credit rule.

You can use both optimistic or pessimistic locking to save-guard your aggregate fields against this kind of race-conditions. Reading Eric Evans DDD carefully he mentions that the “Aggregate Root” (Account in our example) needs a locking mechanism.

Optimistic locking is as easy as adding a version column:

<?php
class Amount
{
    /** @Column(type="integer") @Version */
    private $version;
}

The previous example would then throw an exception in the face of whatever request saves the entity last (and would create the inconsistent state).

Pessimmistic locking requires an additional flag set on the EntityManager::find() call, enabling write locking directly in the database using a FOR UPDATE.

<?php
use Doctrine\DBAL\LockMode;

$account = $em->find('Bank\Entities\Account', $accId, LockMode::PESSIMISTIC_READ);

Keeping Updates and Deletes in Sync

The example shown in this article does not allow changes to the value in Entry, which considerably simplifies the effort to keep Account::$balance in sync. If your use-case allows fields to be updated or related entities to be removed you have to encapsulate this logic in your “Aggregate Root” entity and adjust the aggregate field accordingly.

Conclusion

This article described how to obtain aggregate values using DQL or your domain model. It showed how you can easily add an aggregate field that offers serious performance benefits over iterating all the related objects that make up an aggregate value. Finally I showed how you can ensure that your aggregate fields do not get out of sync due to race-conditions and concurrent access.

]]>
Wed, 07 Jul 2010 00:00:00 +0000
http://www.doctrine-project.org/2010/06/15/doctrine2-beta2-released.html http://www.doctrine-project.org/2010/06/15/doctrine2-beta2-released.html <![CDATA[Doctrine2 BETA2 Released]]>

Doctrine2 BETA2 Released

Today we are happy to announce the immediate availability of the second beta version of Doctrine2. This is the first release after the split of Doctrine2 into three independent projects, Common, DBAL and ORM. This change took longer than we expected but we are back to our SVN productivity now and strive to surpass it utilizing Git.

Beta 2 is a completely backwards compatible release and over 60 issues and bugs have been closed in total. The following larger changes have been introduced from Doctrine2 Beta 1:

Common

  • Added ClassLoader#classExists as well as ClassLoader#getClassLoader methods DCOM-7
  • Changes to Annotation Parser with regards to Autoloading Annotation Classes

DBAL

  • New Driver support for Microsoft PDO Sqlsrv Extension DBAL-10
  • Fixed Mssql/Sqlsrv Platforms and SchemaManager DBAL-8
  • New Driver and Platform Support for DB2 (PDO_DB2 and IBM_DB2 Extensions) DDC-494

ORM

  • Basic Pessimistic Locking support using FOR UPDATE or vendor specific shared locks DDC-178
  • Added a Validate Mapping CLI Task DDC-515

Download

You can get the code a few different ways which are described in detail here. If you have any issues with Doctrine you can report them on Jira.

Contributions

We thank all the contributors and early adopters for their extensive feedback and reports. If you are interesting in contributing to the Doctrine project too, check out our new contributors guide and community page for information about how you can get involved!

]]>
Tue, 15 Jun 2010 00:00:00 +0000
http://www.doctrine-project.org/2010/06/09/doctrine-mongodb-odm-1-0-0alpha1-released.html http://www.doctrine-project.org/2010/06/09/doctrine-mongodb-odm-1-0-0alpha1-released.html <![CDATA[Doctrine MongoDB ODM 1.0.0ALPHA1 Released]]>

Doctrine MongoDB ODM 1.0.0ALPHA1 Released

Today I am very happy to announce the release of the first alpha version of the Doctrine MongoDB Object Document Mapper. This is exciting as it is the beginning of a whole new chapter in the life of the Doctrine Project. We hope to continue adding packages to allow you to transparently persist your domain objects to a variety of different database engines!

Features

Below you will find a list of some of the features provided by the Doctrine MongoDB Object Document Mapper:

  • Transparent persistence.
  • Map one or many embedded documents.
  • Map one or many referenced documents.
  • Create references between documents in different databases.
  • Map documents with Annotations , XML , YAML or plain old PHP code.
  • Documents can be stored on the MongoGridFS.
  • Collection per class(concrete) and single collection inheritance supported.
  • Map your Doctrine 2 ORM Entities to the ODM and use mixed data stores.
  • Inserts are performed using MongoCollection::batchInsert()
  • Updates are performed using the atomic operators $set, $pullAll, $pushAll and $increment instead of saving the entire document.
  • Migrate your schema as your domain model evolves and changes.
  • Fluent Object Oriented Interface for building and executing queries.
  • Map Reduce integration.

You can continue reading the Introduction chapter in the reference documentation to get a grasp of what exactly the Doctrine MongoDB Object Document Mapper does by looking at some examples!

Documentation

Want documentation? You got it! Check out the links below to get started learning about the Doctrine MongoDB Object Document Mapper:

We’ll be adding more Cookbook articles in the coming weeks so check back for more documentation!

Download

You can see all the download information for the Doctrine MongoDB ODM on the projects download page. You have several ways to get the code which are described below as well:

Checkout from Git

$ git clone git://github.com/doctrine/mongodb-odm.git mongodb_odm
$ cd mongodb_odm
$ git checkout 1.0.0ALPHA1

Download PEAR Package

You can manually download the PEAR package here. If you want you can manually unarchive the code or you can pear install the downloaded package:

$ pear install /path/to/downloads/DoctrineMongoDBODM-1.0.0ALPHA1.tgz

Install from PEAR

You can also directly install using our PEAR Server:

$ pear install pear.doctrine-project.org/DoctrineMongoDBODM-1.0.0ALPHA1

Reporting Issues

If you encounter any problems with the Doctrine MongoDB Object Document Mapper you can report new issues to the Jira project. For more information about contributing to Doctrine you can checkout the documentation for our Contributor Workflow.

]]>
Wed, 09 Jun 2010 00:00:00 +0000
http://www.doctrine-project.org/2010/05/27/bringing-it-all-together.html http://www.doctrine-project.org/2010/05/27/bringing-it-all-together.html <![CDATA[Bringing it all together]]>

Bringing it all together

Recently we’ve been making some pretty serious changes around here. This blog post aims to overview it all and make sure people are aware of what is going on!

Website Changes

A few weeks ago I made some updates to the Doctrine website. Some said it looked like we took a step backwards. Well, we kind of did. I had to rip apart the website, remove old legacy code and reorganize things so that it can be integrated with the changes we wanted to make next. So I’ve sort of had to tear it all apart and put it back together a new way. It’s been a bumpy road but we’re starting to get the remaining issues worked out.

The Switch to git

The next big change we wanted to make was to switch to github.com for our source control. This has a lot of impact on the project since everything is built around the source control, including the website. That is why the previous change was necessary in order to make this move complete.

Splitting Doctrine 2 Sources

The next step for us was to split the Doctrine 2 sources into separate repositories on github. So now the source code of the Common, DBAL, and ORM packages are truly separated.

This means the packages can evolve independently and will be maintained separately from now on. The website also has dedicated project pages for the DBAL and ORM with plenty of documentation.

Bringing it all together

The last piece that brings it all together is the new Guide for Doctrine Contributors and Collaborators. Now that we’ve moved to git we had to reinvent a lot of stuff we had already learned for SVN. Thanks to our git mentor David Abdemoulaie (hobodave) we have figured out a workable solution for dealing with the project dependencies via git submodules that does most of what we want. Through this process we all worked on some new documentation that detailed how contributors and collaborators for the Doctrine Project should work. We really hope that this will help get people involved with the project and mature things more.

]]>
Thu, 27 May 2010 00:00:00 +0000
http://www.doctrine-project.org/2010/05/13/the-switch-to-git.html http://www.doctrine-project.org/2010/05/13/the-switch-to-git.html <![CDATA[The Switch to git]]>

The Switch to git

Now that the dust has settled from the move to git I suppose it is time for a blog post. About a month ago, we made the decision to switch the Doctrine projects source control to git. Like many other open source projects , we also chose github.com to host our repositories. Github brings a whole new level of collaborative coding to the Doctrine community and I can already see more people getting involved because of it.

Still want to use SVN?

If you still want to use subversion externals in your project, you can do so by using the read-only SVN features of github.com:

You can read about this feature on the github blog.

Need to learn git?

Through the process of moving to git, we have all had to learn lots but it could not have been done without the Pro Git Book. It is an awesome book written by Scott Chacon who works at github and is a git guru among other things.. The book can be ordered or can be read online for free!

Want to contribute to Doctrine?

If you are interested in contributing to the Doctrine project, you will need to fork one of the Doctrine repositories and submit your modifications. You can read more about how to “Fork a project and submit your modifications” on the github website.

]]>
Thu, 13 May 2010 00:00:00 +0000
http://www.doctrine-project.org/2010/05/13/doctrine-mongodb-object-document-mapper.html http://www.doctrine-project.org/2010/05/13/doctrine-mongodb-object-document-mapper.html <![CDATA[Doctrine MongoDB Object Document Mapper]]>

Doctrine MongoDB Object Document Mapper

A question asked to me many times by many different people over the last year is, “will Doctrine ever have any support for MongoDB?”. I have never really had an answer because we haven’t had any official plans to support it as it was so new to the database world and php so nobody really knew much about it yet.

A few weekends ago I decided to install MongoDB and give it a try. It was pretty fun and interesting. I quickly learned that it being a document based storage system lends itself well to a object mapper so the experimental Doctrine MongoDB Object Document Mapper was born.

Introducing Doctrine MongoDB Object Document Mapper (ODM)

Much like the Doctrine 2 ORM, the ODM aims to provide transparent persistence for PHP 5.3.0+ objects. You will notice that the Doctrine 2 ORM and ODM infrastructure, style, interfaces, etc. are all very similar. Instead of an EntityManager like in the ORM you have the DocumentManager. Map your objects in the same way you do for the ORM. Here is an examle User document:

<?php
/** @Document(db="my_db", collection="users") */
class User
{
    /** @Id */
    private $id;

    /** @String */
    private $username;

    /** @String */
    private $password;

    // ...
}

Now like you would expect you can create new instances and persist them to Mongo:

<?php
$user = new User();
$user->setUsername('jwage');
$user->setPassword('testing');

$dm->persist($user);
$dm->flush();

Now if you have a look in MongoDB you will see a database named my_db and a collection named users containing a new document like the following:

array(
  '_id' => instanceof MongoId,
  'username' => 'jwage',
  'password' => 'testing'
)

When you query for and retrieve this document from the database later, Doctrine reconstructs the PHP object with the data from MongoDB:

<?php
$user = $dm->findOne('User', array('username' => 'jwage')); // instanceof User
echo $user->getUsername();

Below you can find an overview list of the features available:

  • Transparent persistence.
  • Map one or many embedded documents.
  • Map one or many referenced documents.
  • Create references between documents in different databases.
  • Map documents with Annotations, XML, YAML or plain old PHP code.
  • Documents can be stored on the MongoGridFS.
  • Collection per class(concrete) and single collection inheritance supported.
  • Map your Doctrine 2 ORM Entities to the ODM and use mixed data stores.
  • Inserts are performed using MongoCollection::batchInsert()
  • Updates are performed using $set instead of saving the entire document.

Getting Started?

We’ve put together a little documentation to help you get familiar with the ODM quickly.

How can I contribute?

Get your fork on! All you need to do is fork a Doctrine repository on github.com and submit your modifications to us by sending a pull request.

You can also take part in discussions on our mailing list or join #doctrine on irc.freenode.net for live support from the community.

]]>
Thu, 13 May 2010 00:00:00 +0000
http://www.doctrine-project.org/2010/05/12/a-few-website-changes.html http://www.doctrine-project.org/2010/05/12/a-few-website-changes.html <![CDATA[Website Updates]]>

Website Updates

As you probably already noticed, the Doctrine website looks a little bit different. In preparation for the Doctrine 2.0 release, the website needed to be improved a little bit to better handle the multiple versions and projects under the Doctrine umbrella. Along the way I did a little spring cleaning of some code from the early Doctrine days as well!

You can now find dedicated sections of the website for both the Object Relational Mapper and Database Abstraction Layer projects:

The new website also introduces a new API Documentation thanks to PHP Doctor!

If you have any problems with the website please let me know by e-mail at jonwage [at] gmail.com.

]]>
Wed, 12 May 2010 00:00:00 +0000
http://www.doctrine-project.org/2010/04/27/doctrine-2-0-0-beta1-released.html http://www.doctrine-project.org/2010/04/27/doctrine-2-0-0-beta1-released.html <![CDATA[Doctrine 2 BETA1 Released]]>

Doctrine 2 BETA1 Released

Today we are pleased to announce the immediate release of the first beta version of Doctrine 2. It comes with some delay which was caused partly by our move to git and github and the switch to the Symfony Console component for the CLI. We had to confront the alpha users with quite some backwards compatibility problems and we apologize for that. Starting with the beta period you can expect the amount of backwards incompatible changes to be much lower.

Since the ALPHA4 release over 160 issues have been resolved. You can find the full changelog here.

Some of the most important changes were the shift towards the Symfony (2) Console component for the CLI as well as the introduction of the inversedBy attribute for bidirectional associations, among others. For some help with upgrading from ALPHA4 to BETA1, please consult the upgrade page.

You can get the new release as usual from our download page or directly from github.

We would like to thank all the adopters of the early alpha releases. All your issue reports, feature and enhancement requests and general feedback and criticism have helped a lot to move the project forward.

Looking forward, we will likely have at least 2 or 3 beta releases, about every 1-2 months, before we go RC. Once that happens, the API is ultimately frozen until the stable release.

]]>
Tue, 27 Apr 2010 00:00:00 +0000
http://www.doctrine-project.org/2010/04/20/orm-is-not-a-choice.html http://www.doctrine-project.org/2010/04/20/orm-is-not-a-choice.html <![CDATA[ORM is Not a Choice]]>

ORM is Not a Choice

NOTE When speaking of “ORM” or “object-relational mapping” in this post I am referring to the act of mapping an object-oriented domain model to a relational database. There are other, alternative forms of object-relational mapping.

“Should I use an ORM?” is a frequently asked question that somehow misses the point, because ORM is usually not some optional thing you can either use or not. The choices are elsewhere. Furthermore, if there is a dislike for ORM tools it helps to clarify what exactly is the cause. The cause can be a dislike of object-oriented domain models. For example, if you prefer to separate data from behavior/logic, as I’ve read recently on Twitter , then it is a sign that you don’t like domain models, at least not rich ones, maybe anemic ones , and you probably don’t like OOP much at all then, because bundling data with behavior is what OO is about, usually.

NOTE It’s OK not to like OOP these days. Its not the holy grail anymore, mostly due to the usually messy concurrency characteristics and problems resulting from typical object-oriented design which revolves around imperative programming with direct manipulation of mutable state, but that does not apply to PHP as much as to some other languages due to its thread-confined nature/execution model.

You can not use a relational database in combination with an object-oriented domain model without mapping.

The choices that lead to the need for ORM are the following:

  • You can choose to use a relational database or not.
  • You can choose to create an object-oriented domain model or not.

If you want a relational database and you want an object-oriented domain model, you need ORM, there is no choice. If you choose to use a relational database but not an object-oriented domain model, you might need some other form of object-relational or other mapping, depending on how you want to model your application and your business logic around the data in particular.

People not being aware of the above two choices, especially the second one, is unfortunately what makes some of them “choose ORM” and then sometimes getting frustrated. Using an ORM without even having or wanting a domain model and with the head still exclusively full of tables and rows, which are at the beginning and at the end of every thought about the software being built, is a wrong choice. With these preconditions, ORM quickly becomes a pain, and its wrong. Forcing your relational data into objects even though you don’t really know what to do with them, maybe it just seems nice to have them as “data containers”, is the wrong motivation. If you don’t want to combine your business data with your business behavior, something that can be done nicely in an OO domain model, then there is not much value in having objects wrapped around your data. Some other, wrong motivations for “choosing an ORM”, at least when they are the main motivations, are:

  • Database vendor independence
  • “Hiding SQL”

These are just additional benefits you can get but they are not the main purpose of an ORM tool. Then what is the main purpose? State management. Synchronizing the state of your in-memory object model with a relational database for the purpose of persistent storage. Neither does an ORM need to be database vendor independent, nor does it need to hide SQL to do this. Everything else is icing on the cake. If all you want is to centralize your database access paths, which is a good thing for caching and all, you don’t need an ORM for that either, any database access layer, existing or self-made, will do.

I hope it is a bit clearer now that ORM is not a choice but a need that results out of other choices.

]]>
Tue, 20 Apr 2010 00:00:00 +0000
http://www.doctrine-project.org/2010/03/29/doctrine2-custom-dql-udfs.html http://www.doctrine-project.org/2010/03/29/doctrine2-custom-dql-udfs.html <![CDATA[Extending DQL in Doctrine 2: User-Defined Functions]]>

Extending DQL in Doctrine 2: User-Defined Functions

By default DQL supports a limited subset of all the vendor-specific SQL functions common between all the vendors. However in many cases once you have decided on a specific database vendor, you will never change it during the life of your project. This decision for a specific vendor potentially allows you to make use of powerful SQL features that are unique to the vendor.

Note

It is worth to mention that Doctrine 2 also allows you to handwrite your SQL instead of extending the DQL parser, which is sort of an advanced extension point. You can map arbitrary SQL to your objects and gain access to vendor specific functionalities using the EntityManager#createNativeQuery() API.

The DQL Parser has hooks to register functions that can then be used in your DQL queries and transformed into SQL, allowing to extend Doctrines Query capabilities to the vendors strength. This post explains the Used-Defined Functions API (UDF) of the Dql Parser and shows some examples to give you some hints how you would extend DQL.

There are three types of functions in DQL, those that return a numerical value, those that return a string and those that return a Date. Your custom method has to be registered as either one of those. The return type information is used by the DQL parser to check possible syntax errors during the parsing process, for example using a string function return value in a math expression.

Registering your own DQL functions

You can register your functions adding them to the ORM configuration:

<?php
$config = new \Doctrine\ORM\Configuration();
$config->addCustomStringFunction($name, $class);
$config->addCustomNumericFunction($name, $class);
$config->addCustomDatetimeFunction($name, $class);

$em = EntityManager::create($dbParams, $config);

The $name is the name the function will be referred to in the DQL query. $class is a string of a class-name which has to extend Doctrine\ORM\Query\Node\FunctionNode. This is a class that offers all the necessary API and methods to implement a UDF.

In this post we will implement some MySql specific Date calculation methods, which are quite handy in my opinion:

Date Diff

Mysql’s DateDiff function takes two dates as argument and calculates the difference in days with date1-date2.

The DQL parser is a top-down recursive descent parser to generate the Abstract-Syntax Tree (AST) and uses a TreeWalker approach to generate the appropriate SQL from the AST. This makes reading the Parser/TreeWalker code managable in a finite amount of time.

The FunctionNode class I referred to earlier requires you to implement two methods, one for the parsing process (obviously) called parse and one for the TreeWalker process called getSql(). I show you the code for the DateDiff method and discuss it step by step:

<?php
/**
 * DateDiffFunction ::= "DATEDIFF" "(" ArithmeticPrimary "," ArithmeticPrimary ")"
 */
class DateDiff extends FunctionNode
{
    // (1)
    public $firstDateExpression = null;
    public $secondDateExpression = null;

    public function parse(\Doctrine\ORM\Query\Parser $parser)
    {
        $parser->match(Lexer::T_IDENTIFIER); // (2)
        $parser->match(Lexer::T_OPEN_PARENTHESIS); // (3)
        $this->firstDateExpression = $parser->ArithmeticPrimary(); // (4)
        $parser->match(Lexer::T_COMMA); // (5)
        $this->secondDateExpression = $parser->ArithmeticPrimary(); // (6)
        $parser->match(Lexer::T_CLOSE_PARENTHESIS); // (3)
    }

    public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
    {
        return 'DATEDIFF(' .
            $this->firstDateExpression->dispatch($sqlWalker) . ', ' .
            $this->secondDateExpression->dispatch($sqlWalker) .
        ')'; // (7)
    }
}

The Parsing process of the DATEDIFF function is going to find two expressions the date1 and the date2 values, whose AST Node representations will be saved in the variables of the DateDiff FunctionNode instance at (1).

The parse() method has to cut the function call “DATEDIFF” and its argument into pieces. Since the parser detects the function using a lookahead the T_IDENTIFIER of the function name has to be taken from the stack (2), followed by a detection of the arguments in (4)-(6). The opening and closing parenthesis have to be detected also. This happens during the Parsing process and leads to the generation of a DateDiff FunctionNode somewhere in the AST of the dql statement.

The ArithmeticPrimary method call is the most common denominator of valid EBNF tokens taken from the DQL EBNF grammer that matches our requirements for valid input into the DateDiff Dql function. Picking the right tokens for your methods is a tricky business, but the EBNF grammer is pretty helpful finding it, as is looking at the Parser source code.

Now in the TreeWalker process we have to pick up this node and generate SQL from it, which apprently is quite easy looking at the code in (7). Since we don’t know which type of AST Node the first and second Date expression are we are just dispatching them back to the SQL Walker to generate SQL from and then wrap our DATEDIFF function call around this output.

Now registering this DateDiff FunctionNode with the ORM using:

<?php
$config = new \Doctrine\ORM\Configuration();
$config->addCustomStringFunction('DATEDIFF', 'DoctrineExtensions\Query\MySql\DateDiff');

We can do fancy stuff like:

[sql]
SELECT p FROM DoctrineExtensions\Query\BlogPost p WHERE DATEDIFF(CURRENT_TIME(), p.created) < 7

Date Add

Often useful it the ability to do some simple date calculations in your DQL query using MySql’s DATE_ADD function.

I’ll skip the bla and show the code for this function:

<?php
/**
 * DateAddFunction ::=
 *     "DATE_ADD" "(" ArithmeticPrimary ", INTERVAL" ArithmeticPrimary Identifier ")"
 */
class DateAdd extends FunctionNode
{
    public $firstDateExpression = null;
    public $intervalExpression = null;
    public $unit = null;

    public function parse(\Doctrine\ORM\Query\Parser $parser)
    {
        $parser->match(Lexer::T_IDENTIFIER);
        $parser->match(Lexer::T_OPEN_PARENTHESIS);

        $this->firstDateExpression = $parser->ArithmeticPrimary();

        $parser->match(Lexer::T_COMMA);
        $parser->match(Lexer::T_IDENTIFIER);

        $this->intervalExpression = $parser->ArithmeticPrimary();

        $parser->match(Lexer::T_IDENTIFIER);

        /* @var $lexer Lexer */
        $lexer = $parser->getLexer();
        $this->unit = $lexer->token['value'];

        $parser->match(Lexer::T_CLOSE_PARENTHESIS);
    }

    public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
    {
        return 'DATE_ADD(' .
            $this->firstDateExpression->dispatch($sqlWalker) . ', INTERVAL ' .
            $this->intervalExpression->dispatch($sqlWalker) . ' ' . $this->unit .
        ')';
    }
}

The only difference compared to the DATEDIFF here is, we additionally need the Lexer to access the value of the T_IDENTIFIER token for the Date Interval unit, for example the MONTH in:

[sql]
SELECT p FROM DoctrineExtensions\Query\BlogPost p WHERE DATE_ADD(CURRENT_TIME(), INTERVAL 4 MONTH) > p.created

The above method now only supports the specification using INTERVAL, to also allow a real date in DATE_ADD we need to add some decision logic to the parsing process (makes up for a nice excercise).

Now as you see, the Parsing process doesn’t catch all the possible SQL errors, here we don’t match for all the valid inputs for the interval unit. However where necessary we rely on the database vendors SQL parser to show us further errors in the parsing process, for example if the Unit would not be one of the supported values by MySql.

Conclusion

Now that you all know how you can implement vendor specific SQL functionalities in DQL, we would be excited to see user extensions that add vendor specific function packages, for example more math functions, XML + GIS Support, Hashing functions and so on.

For 2.0 we will come with the current set of functions, however for a future version we will re-evaluate if we can abstract even more vendor sql functions and extend the DQL languages scope.

Code for this Extension to DQL and other Doctrine Extensions can be found in my Github DoctrineExtensions repository.

]]>
Mon, 29 Mar 2010 00:00:00 +0000
http://www.doctrine-project.org/2010/03/29/doctrine-1-2-2-released.html http://www.doctrine-project.org/2010/03/29/doctrine-1-2-2-released.html <![CDATA[Doctrine 1.2.2 Released]]>

Doctrine 1.2.2 Released

Today I am happy to bring you the second maintenance release for the 1.2 version of Doctrine. This release contains around 100 fixed issues from Jira. We will continue regularly creating maintenance releases for the Doctrine 1.2 version so if you have any problems, please create a issue on Jira, include a patch with tests and we’ll try and include it in the next version.

As always you can find information about this new version on the download page.

]]>
Mon, 29 Mar 2010 00:00:00 +0000
http://www.doctrine-project.org/2010/03/21/doctrine-2-give-me-my-constructor-back.html http://www.doctrine-project.org/2010/03/21/doctrine-2-give-me-my-constructor-back.html <![CDATA[Doctrine 2: Give me my constructor back]]>

Doctrine 2: Give me my constructor back

At ConFoo 2010 during my presentation, someone asked about the constructor of entities in Doctrine 2 and whether or not it could be used. I think this is something worth writing about since in Doctrine 1 this was not possible. The constructor was hi-jacked from you and used internally by Doctrine.

In Doctrine 2 it is possible to define the constructor in your entity classes and is not required to be a zero argument constructor! That’s right, Doctrine 2 never instantiates the constructor of your entities so you have complete control!

This is possible due to a small trick which is used by two other projects, php-object-freezer and Flow3. The gist of it is we store a prototype class instance that is unserialized from a hand crafted serialized string where the class name is concatenated into the string. The result when we unserialize the string is an instance of the class which is stored as a prototype and cloned everytime we need a new instance during hydration.

Have a look at the method responsible for this:

<?php
public function newInstance()
{
    if ($this->_prototype === null) {
        $this->_prototype = unserialize(sprintf('O:%d:"%s":0:{}', strlen($this->name), $this->name));
    }
    return clone $this->_prototype;
}

The above code allows us to have entities where we make full use of our constructor like the following class definition:

<?php
namespace Entities;

/** @Entity */
class User
{
    /** @Column */
    private $username;

    /** @Column */
    private $password;

    public function __construct($username, $password)
    {
        $this->username = $username;
        $this->password = md5($password);
    }
}

Now of course you can use the constructor like you would expect:

<?php
use Entities\User;

$user = new User('jwage', 'changeme');

Conclusion

It is an interesting solution and did not have much if any effect on hydration performance. At any rate the cost is well worth it to get complete control of your entities. No longer are the days where Doctrine greedily steals your precious class constructor!

]]>
Sun, 21 Mar 2010 00:00:00 +0000
http://www.doctrine-project.org/2010/03/17/doctrine-performance-revisited.html http://www.doctrine-project.org/2010/03/17/doctrine-performance-revisited.html <![CDATA[Doctrine Performance Revisited]]>

Doctrine Performance Revisited

In our ever-lasting quest to provide a powerful, flexible and yet performant ORM experience we are often confronted with benchmarks and have been talking about performance topics since last year in several talks at many different conferences, and Roman has talked about his opinion on such benchmarks on this blog.

Recently Francois Zaninotto, lead developer of the soon to be released Propel 1.5 (currently in beta) wrote a blog post comparing performance mainly of the different Propel 1.x versions with and without caching and against a PDO benchmark. The benchmark also contains a test for Doctrine 1.2.

It is important to note that the PDO test only shows the “baseline” performance, that is, it does not even remotely “do the same thing” as the others. No object creation, no hydration of objects from result rows, no identity management, no change tracking, nothing. So dont get the numbers wrong. If you would want to get at least remotely the same result as the ORMs provide with a raw PDO/SQL “benchmark”, you would need quite some custom coding and, if you dont want to copy/paste all day, introduce some abstraction.

The following scenarios are compared in the benchmark:

  • Scenario 1: Create a new Model object, set its columns, and save it. Tests Model object speed, and INSERT SQL generation.
  • Scenario 2: Lookup a record by its primary key. Tests basic query and hydration.
  • Scenario 3: Lookup a record using a complex query. Tests object query speed.
  • Scenario 4: Lookup 5 records on a simple criterion. Tests hydration speed.
  • Scenario 5: Lookup a record and hydrate it together with its related record in another table. Tests join hydration speed.

I reproduced the complete table of results here for comparison since my machine is generating very different overall times than the ones generated by Francois. Each Scenario is executed several times and the sum of execution times is printed. After each run the identity maps are wiped so that objects are not reused. All the tests use an SQLite In-Memory database, are run on PHP 5.3 and of course use an opcode cache (APC).

A first version of the corresponding Doctrine 2 benchmarks was added today to the SVN repository by Roman They can all be run from your machine directly after checkout.

Here are my results:

                             | Insert | findPk | complex| hydrate|  with  |
                             |--------|--------|--------|--------|--------|
                PDOTestSuite |    132 |    149 |    112 |    107 |    109 |
           Propel14TestSuite |    953 |    436 |    133 |    270 |    280 |
      Propel15aLa14TestSuite |    926 |    428 |    143 |    264 |    282 |
           Propel15TestSuite |    923 |    558 |    171 |    356 |    385 |
  Propel15WithCacheTestSuite |    932 |    463 |    189 |    342 |    327 |
         Doctrine12TestSuite |   1673 |   2661 |    449 |   1710 |   1832 |
Doctrine12WithCacheTestSuite |   1903 |   1179 |    550 |    957 |    722 |
          Doctrine2TestSuite |    165 |    426 |    412 |   1048 |   1042 |
 Doctrine2WithCacheTestSuite |    176 |    423 |    148 |    606 |    383 |

These are the key observations for the Doctrine 2 results.

Doctrine 2 Insert Performance

This is mainly a result of the rather strange test. Its basically a mass-insert. All the insert tests seem to use a single database transaction, so its comparable to a mass-insert on a single request. As such the result is not surprising since we know that Doctrine 2 can effectively batch inserts. Mind you that mass-inserts are not really a focus of an ORM and not a realistic scenario in most applications. So take this test with a grain of salt, its a mass-insert test. If you’re looking for the ORM with the fastest mass-inserts, you can stop now, you found it.

Doctrine 2 Find By Primary Key Performance

Doctrine 2 Find Entity By Primary Key performance seems to be roughly three times as slow as handcrafted PDO (that doesnt do anything besides executing the query, mind you...). The good results in this test, especially compared to Doctrine 1, come from the fact that there is not much abstraction for all kinds of find*() operations going on. SQL is created, executed and the results turned into objects without much hoopla.

Doctrine 2 Complex Query Performance

The complex query is a scalar count query. See the Doctrine 2 code for this scenario:

<?php
$authors = $this->em->createQuery(
    'SELECT count(a.id) AS num FROM Author a WHERE a.id > ?1 OR CONCAT(a.firstName, a.lastName) = ?2'
)->setParameter(1, $this->authors[array_rand($this->authors)]->id)
 ->setParameter(2, 'John Doe')
 ->getSingleScalarResult();

The getSingleScalarResult() method that executes the query uses a very minimalistic hydration mode that only grabs the first value of the first result column. Therefore in combination with the DQL to SQL Query Parser Cache (Doctrine2WithCacheTestSuite) we get a result almost as fast result as the PDO handcrafted scenario, because we essentially get the transformed SQL query from the cache for this DQL, execute it and grab the value.

Hydration Performance (Scenario 4 and 5)

In the field of hydration Doctrine 2 is either equally fast or seems “only” up to 40% slower than Propel 1.4 or Propel 1.5 based on the two scenarios. The main reason here is really only that since Doctrine 2 provides transparent persistence, it can not give lazy-loading through base classes, instead it needs to inject proxy objects as stubs into the entities. That simply means Doctrine needs to create more objects than propel, thats it. Note that once the objects would actually be lazy-loaded, Propel would need to create these objects, too. The difference is that Doctrine needs to create them beforehand. When they lazy-load, no new object is created, the proxies simply populate themselves with the data.

A main difference, however, is that the hydration code of Doctrine is completely generic. That means this same code can handle all kinds of different SQL results correctly, no matter how many nested joins, scalar values, aggregate values there are in the result and it can even deal with strangely ordered collections in result sets (You get such stuff with multiple order by clauses on different fields which order in different directions. Combine such ordering with joining collections and you get a pretty funky SQL result set).

The general approach in algorithms from the Doctrine 1.2 Hydrators were re-used in Doctrine 2. However, optimizations in the data structures and use of the fastest internal php methods (as fast as you can get with php, you know ;)) made it possible to optimize the code to yield the shown results.

Interesting here is maybe that Doctrine 2 without caching is all in all still a lot faster than Doctrine 1 with caching, so this looks like a good improvement. Furthermore, the query cache in Doctrine 2 is very effective and almost completely removes all the overhead of DQL. The query cache is what allows us to provide this extremely powerful abstraction that is immensely flexible. If you dont like DQL yet, you should read up on domain-specific languages and object query languages in particular. It’s a gem and cornerstone of this project and if you dont like it we can’t help you.

Hydration with non Object Results

Putting aside the boring Propel comparisons, lets get to something Doctrine-specific. Because we know that read performance is very important and object instances are not necessary all the time, Doctrine 2, just like Doctrine 1, provides many different levels of abstraction in-between objects and raw PDO/SQL result sets that you can go up and down as you wish.

The main two intermediate levels are array graphs and flat, scalar result sets (which are still not the same as the raw SQL result sets because type conversions and column name to field name conversions still take place).

These alternative result formats perform as follows:

                               | Insert | findPk | complex| hydrate|  with  |
                               |--------|--------|--------|--------|--------|
Dc2ArrayHydrateTestSuite       |    172 |    421 |    145 |    332 |    285 |
Dc2ScalarHydrateTestSuite      |    175 |    424 |    145 |    251 |    245 |
Dc2WithoutProxiesTestSuite     |    174 |    423 |    148 |    483 |    628 |

The first method “Without Proxies” still creates object instances, however, it does not replace loose ends of the object graph with lazy-load proxies. Be careful with such optimizations in practice because partial objects can be fragile to work with. The important point here is that different levels of optimization are there when needed, before you need to finally drop all abstraction and deal with PDO/SQL directly (which is not bad, you know, just often not very convenient, flexible and/or robust against refactorings or schema changes).

The Array Hydration (getArrayResult()) returns a nested array structure that is comparable to an object graph. Most of the time you can think of it as a performant read-only “view” of an object graph. In the case of Books with Authors the result looks like:

array(1) {
  [0]=>
  &array(5) {
    ["id"]=>
    int(1)
    ["title"]=>
    string(6) "Hello0"
    ["isbn"]=>
    string(4) "1234"
    ["price"]=>
    float(0)
    ["author"]=>
    &array(4) {
      ["id"]=>
      int(1143)
      ["firstName"]=>
      string(8) "John1142"
      ["lastName"]=>
      string(7) "Doe1142"
      ["email"]=>
      NULL
    }
  }

These array graphs can be built from basically any query. Its backed by roughly the same algorithm that allows the arbitrary object hydration with indefinite joins and even scalar and aggregate values in between.

In the case where your objects implement ArrayAccess, you can often use object and array results interchangeably without the need to update view code.

Conclusion

What that all means is mainly that if you have an application that looks (almost) exactly like the benchmarking code used here, then you (maybe) got some useful numbers to look at, otherwise ... not.

Apart from that we hope this convinces you that we’re not wasting your CPU cycles on purpose. Doctrine 2 is a huge balancing act between flexibility, features and performance and it worked out well so far.

]]>
Wed, 17 Mar 2010 00:00:00 +0000
http://www.doctrine-project.org/2010/03/15/what-to-expect-from-doctrine-1.html http://www.doctrine-project.org/2010/03/15/what-to-expect-from-doctrine-1.html <![CDATA[What to expect from Doctrine 1]]>

What to expect from Doctrine 1

As you all can obviously see, our focus around here these days has been on Doctrine 2. While overall this is a great thing, we still have a stable Doctrine 1.2 version to maintain. This blog post will give you a little information about Doctrine 1.0, 1.1 and 1.2.

Doctrine 1.0 and 1.1 End of Life

You may not have noticed, but the end of life for Doctrine 1.0 and 1.1 has come and gone earlier in the year. As of right now we will not be committing anymore bug fixes to these branches. All development resources will now focus on finishing Doctrine 2 and maintaining 1.2.

Doctrine 1.2 Maintenance Releases

Since Doctrine 1.2 is the last stable version to be released for the Doctrine 1 series, we decided to open up the development a little bit for the maintenance releases. Previously we were very strict with only allowing bug fixes, but we will now allow a little more flexibility to the types of things we commit to these releases. They can now contain small enhancements and improvements as long as they do not break backwards compatibility. Of course when adding things we cannot always be 100% sure that something is BC, so we will announce each 1.2.x release one week prior to it’s packaging and deployment in order to give people time to test things in SVN.

The reasoning behind this move is because we want to still improve the small usability issues of the Doctrine 1 series without having to commit to entirely new major versions. This way we are not leaving the Doctrine 1 code behind while we’re focusing on the Doctrine 2 version. We hope that you all are okay with this move. If you have any issues please let us know!

]]>
Mon, 15 Mar 2010 00:00:00 +0000
http://www.doctrine-project.org/2010/03/15/doctrine-2-at-confoo-2010.html http://www.doctrine-project.org/2010/03/15/doctrine-2-at-confoo-2010.html <![CDATA[Doctrine 2 at ConFoo 2010]]>

Doctrine 2 at ConFoo 2010

This past week I was lucky enough to get to travel to Montreal for the annual ConFoo conference, previously known as PHP Quebec. I presented on the latest and greatest version of Doctrine, 2.0 for the PHP Trac. You can find the slides on SlideShare.com here or view the presentation embedded below:

Doctrine 2 - Enterprise Persistence Layer For PHP

View more presentations from Jonathan Wage.

]]> Mon, 15 Mar 2010 00:00:00 +0000 http://www.doctrine-project.org/2010/03/13/doctrine2-validations.html http://www.doctrine-project.org/2010/03/13/doctrine2-validations.html <![CDATA[Validation of Doctrine 2 Entities]]>

Validation of Doctrine 2 Entities

While Doctrine 1 had validation nested inside the Doctrine_Record instance this is not the case in Doctrine 2 anymore. We won’t ship Doctrine 2 with any validators, the reason being that we think all the frameworks out there already ship with quite decents ones that can be integrated into your Domain easily. Besides us being ORM experts not wanting to maintain yet another validation library, moving the responsibility of validation into the domain layer also allows you to integrate it much easier into frameworks form libraries for example.

What we do offer are hooks to execute any kind of validation inside the Doctrine ORM.

Entities can register lifecycle event methods with Doctrine that are called on different occasions. For validation we would need to hook into the events called before persisting and updating. Even though we don’t support validation out of the box, the implementation is even simpler than in Doctrine 1 and you will get the additional benefit of being able to re-use your validation in any other part of your domain.

Say we have an Order with several OrderLine instances. We never want to allow any customer to order for a larger sum than he is allowed to:

<?php
class Order
{
    public function assertCustomerAllowedBuying()
    {
        $orderLimit = $this->customer->getOrderLimit();

        $amount = 0;
        foreach ($this->orderLines AS $line) {
            $amount += $line->getAmount();
        }

        if ($amount > $orderLimit) {
            throw new CustomerOrderLimitExceededException();
        }
    }
}

Now this is some pretty important piece of business logic in your code, enforcing it at any time is important so that customers with a unknown reputation don’t owe your business too much money.

We can enforce this constraint in any of the metadata drivers. First Annotations:

<?php
/**
 * @Entity
 * @HasLifecycleCallbacks
 */
class Order
{
    /**
     * @PrePersist @PreUpdate
     */
    public function assertCustomerAllowedBuying() {}
}

In XML Mappings:

[xml]
<doctrine-mapping>
    <entity name="Order">
        <lifecycle-callbacks>
            <lifecycle-callback type="prePersist" method="assertCustomerAllowedBuying" />
            <lifecycle-callback type="preUpdate" method="assertCustomerAllowedBuying" />
        </lifecycle-callbacks>
    </entity>
</doctirne-mapping>

YAML needs some little change yet, to allow multiple lifecycle events for one method, this will happen before Beta 1 though.

Now validation is performed whenever you call EntityManager#persist($order) or when you call EntityManager#flush() and an order is about to be updated. Any Exception that happens in the lifecycle callbacks will be catched by the EntityManager and the current transaction is rolled back.

Of course you can do any type of primitive checks, not null, email-validation, string size, integer and date ranges in your validation callbacks.

<?php
class Order
{
    /**
     * @PrePersist @PreUpdate
     */
    public function validate()
    {
        if (!($this->plannedShipDate instanceof DateTime)) {
            throw new ValidateException();
        }

        if ($this->plannedShipDate->format('U') < time()) {
            throw new ValidateException();
        }

        if ($this->customer == null) {
            throw new OrderRequiresCustomerException();
        }
    }
}

What is nice about lifecycle events is, you can also re-use the methods at other places in your domain, for example in combination with your form library. Additionally there is no limitation in the number of methods you register on one particular event, i.e. you can register multiple methods for validation in “PrePersist” or “PreUpdate” or mix and share them in any combinations between those two events.

There is no limit to what you can and can’t validate in “PrePersist” and “PreUpdate” aslong as you don’t create new entity instances. This was already discussed in the previous blog post on the Versionable extension, which requires another type of event called “onFlush”.

Also read:

]]>
Sat, 13 Mar 2010 00:00:00 +0000
http://www.doctrine-project.org/2010/03/01/introduction-to-doctrine-2-webinar.html http://www.doctrine-project.org/2010/03/01/introduction-to-doctrine-2-webinar.html <![CDATA[Introduction to Doctrine 2 Webinar]]>

Introduction to Doctrine 2 Webinar

]]>
Mon, 01 Mar 2010 00:00:00 +0000
http://www.doctrine-project.org/2010/02/24/doctrine2-versionable.html http://www.doctrine-project.org/2010/02/24/doctrine2-versionable.html <![CDATA[A re-usable Versionable Behavior for Doctrine 2]]>

A re-usable Versionable Behavior for Doctrine 2

NOTE This blog entry relates to an outdated Doctrine 2 Alpha version. Please see the documentation for the most up to date behavior. A test-implementation for this behavior is on github.com/beberlei/DoctrineExtensions

My previous post on behaviors in Doctrine 2 generated quite some discussion about the difference on behaviours that are re-usable across models and the trivial specific implementations I have shown.

In this post I will show a re-usable versionable (audit-log) behavior. For this we will need the following ingredients:

  • An interface DoctrineExtensions\Versionable\Versionable

  • A class DoctrineExtensions\Versionable\VersionManager

  • An event listener DoctrineExtensions\Versionable\VersionListener

  • A generic entity DoctrineExtensions\Versionable\ResourceVersion

    NOTE The Event API is currently in the central focus of our efforts so the API shown here may change before the first Beta release.

The workflow is as follows, each Entity that is supposed to be versionable has to implement the interface Versionable which looks like this:

<?php
namespace DoctrineExtensions\Versionable;

interface Versionable
{
    /**
     * @return int
     */
    public function getCurrentVersion();

    /**
     * @return array
     */
    public function getVersionedData();

    /**
     * @return int
     */
    public function getResourceId();
}

Whenever an entity is persisted or updated the state that is persisted will also be logged in an audit table. The state is returned with an array of key value pairs in the getVersionedData() and the current version has to be the value of the @Version column of the entity.

To sum up, the requirements of an entity that can be a Versionable in this simple implementation:

  • Single Integer Primary Key.
  • Has to be versioned with an integer column.

How does such versioned data look like? The generic resource version entity looks like this. Its a Doctrine Entity, but in a domain model its an immutable value object. It should not be changed after creation.

<?php
namespace DoctrineExtensions\Versionable;

class ResourceVersion
{
    /** @Id @Column(type="integer") */
    private $id;

    /** @Column(type="string") */
    private $resourceName;

    /** @Column(type="integer") */
    private $resourceId;

    /** @Column(type="array") */
    private $versionedData;

    /**
     * @Column(type="integer") */
    private $version;

    /** @Column(type="datetime") */
    private $snapshotDate;

    public function __construct(Versionable $resource)
    {
        $this->resourceName = get_class($resource);
        $this->resourceId = $resource->getResourceId();
        $this->versionedData = $resource->getVersionedData();
        $this->version = $resource->getCurrentVersion();
        $this->snapshotDate = new \DateTime("now");
    }

    // getters
}

Now we need to solve the problem of generating the ResourceVersion whenever an Versionable entity is persisted or updated. This can be done by using the Doctrine EventManager API. We will implement the EventSubscriber interface and hook into the “onFlush” event.

<?php
namespace DoctrineExtensions\Versionable;

use Doctrine\Common\EventSubscriber,
    Doctrine\ORM\Events,
    Doctrine\ORM\Event\OnFlushEventArgs,
    Doctrine\ORM\EntityManager;

class VersionListener implements EventSubscriber
{
    public function getSubscribedEvents()
    {
        return array(Events::onFlush);
    }

    public function onFlush(OnFlushEventArgs $args)
    {
        $em = $args->getEntityManager();
        $uow = $em->getUnitOfWork();

        foreach ($uow->getScheduledEntityInsertions() AS $entity) {
            if ($entity instanceof Versionable) {
                $this->_makeSnapshot($entity);
            }
        }

        foreach ($uow->getScheduledEntityUpdates() AS $entity) {
            if ($entity instanceof Versionable) {
                $this->_makeSnapshot($entity);
            }
        }
    }

    private function _makeSnapshot($entity)
    {
        $resourceVersion = new ResourceVersion($entity);
        $class = $this->_em->getClassMetadata(get_class($resourceVersion));

        $this->_em->persist( $resourceVersion );
        $this->_em->getUnitOfWork()->computeChangeSet($class, $resourceVersion);
    }
}

How do we hook this VersionListener into the EntityManager? We will wrap the VersionManager around it that handles registration and offers some convenience methods to retrieve the versions of a resource.

<?php
namespace DoctrineExtensions\Versionable;

use Doctrine\ORM\EntityManager;

class VersionManager
{
    private $_em;

    public function __construct(EntityManager $em)
    {
        $this->_em = $em;
        $this->_em->getEventManager()->addEventSubscriber(
            new VersionListener()
        );
    }

    public function getVersions(Versionable $resource)
    {
        $query = $this->_em->createQuery(
            "SELECT v FROM DoctrineExtensions\Versionable\ResourceVersion v INDEX BY v.version ".
            "WHERE v.resourceName = ?1 AND v.resourceId = ?2 ORDER BY v.version DESC");
        $query->setParameter(1, get_class($resource));
        $query->setParameter(2, $resource->getResourceId());

        return $query->getResult();
    }
}

Now using this to retrieve all the versions of a given entity that is versionable you would go and:

<?php
// $em EntityManager, $blogPost my Blog Post

$versionManager = new VersionManager($em);
$versions = $versionManager->getVersions($blogPost);

echo "Old Title: ".$versions[$oldVersionNum]->getVersionedData('title');

// Create a new version
$blogPost->setTitle("My very new title");
$em->flush();

This is a first example of how to use the powerful Doctrine 2 Event API. It is certainly not easy to use, as you need to understand the inner workings of the UnitOfWork and the different steps it is in during the flush process. However you can generate huge benefits in reusability.

The versionable behaviour could be extended by the following features:

  • Create a new interface Revertable that extends Versionable and add a method revert(Revertable $resource, $toVersion) to the VersionManager that handles the retrieval, invoking of revert and such.
  • Create a new interface Diffable with a method diff($aVersion, $bVersion) and new method diff(Diffable $resource, $aId, $bId) to the VersionManager that handles the delegation of a difference computation between two versions to the Diffable implementor.

Another approach would be not to save the complete state of an entity during the flush operation, but only the fields that changed. This is generally called an AuditLog. We could add an Auditable interface much in the same manner than the Versionable and retrieve the ChangeSets of each entity during flush using the following event listener:

<?php
class AuditListener implements EventSubscriber
{
    public function getSubscribedEvents()
    {
        return array(Events::onFlush);
    }

    public function onFlush(OnFlushEventArgs $args)
    {
        $em = $args->getEntityManager();
        $uow = $em->getUnitOfWork();

        $changeDate = new DateTime("now");
        $class = $em->getClassMetadata('DoctrineExtensions\Auditable\AuditEntry');

        foreach ($uow->getScheduledEntityUpdates() AS $entity) {
            if ($entity instanceof Auditable) {
                $changeSet = $uow->getEntityChangeSet($entity);

                foreach ($changeSet AS $field => $vals) {
                    list($oldValue, $newValue) = $vals;
                    $audit = new AuditEntry(
                        $entity->getResourceName(),
                        $entity->getId(),
                        $oldValue,
                        $newValue,
                        $changeDate
                    );

                    $em->persist($audit);
                    $em->getUnitOfWork()
                       ->computeChangeSet($class, $audit);
                }
            }
        }
    }
}

This approach can also be re-used or combined with several similiar behaviours, like Taggable, Blamable, Commentable.

]]>
Wed, 24 Feb 2010 00:00:00 +0000
http://www.doctrine-project.org/2010/02/18/symfony-live-2010.html http://www.doctrine-project.org/2010/02/18/symfony-live-2010.html <![CDATA[Symfony Live 2010]]>

Symfony Live 2010

This past week I had the pleasure of spending time in Paris, France for the 2010 Symfony Live conference. My first Symfony event was Symfony Camp in 2008 which was a great success. I also attended the first Symfony Live last year where I spoke about Sympal and Doctrine. This time around the Symfony conference was an even bigger success! The community around Symfony and Doctrine has grown a great amount over the years and the event shows that! Many great speakers and topics were present at the conference and it was very exciting to get to be a part of it.

On the first day of the conference I was invited to speak about the latest Doctrine 2! This is perfect timing as Fabien Potencier made available the source code of Symfony 2 the following day. I am very excited about what the future holds for PHP in the coming years as Symfony 2 and Doctrine 2 are really revolutionary PHP projects!

You can find the presentations given at the conference related to Doctrine below:

]]>
Thu, 18 Feb 2010 00:00:00 +0000
http://www.doctrine-project.org/2010/02/17/doctrine2-behaviours-nutshell.html http://www.doctrine-project.org/2010/02/17/doctrine2-behaviours-nutshell.html <![CDATA[Doctrine 2 "Behaviours" in a Nutshell]]>

Doctrine 2 “Behaviours” in a Nutshell

NOTE This blog entry relates to an outdated Doctrine 2 Alpha version. Please see the documentation for the most up to date behavior.

One of the most common fallacies out there about Doctrine 2 abandoning Behaviours is that developers now have to implement fancy logic to re-implement them yourself. Doctrine 2’s approach to completly separate ORM from your domain classes allows to build behaviours in a very clean, unobstrusive and simple object-oriented way. This article shows you how to implement some of the Doctrine 1 behaviours in your Doctrine 2 code. For this I will rewrite the Doctrine 1.x manuals examples for each Behaviour.

This example uses Annotations as example, yet this of course works with YAML and XML mappings. Additionally Doctrine 2 allows constructors to have required arguments as of a commit of the last week. This allows for some pretty slick enforcements in user-land code as you will see in this post.

Straightforward combination of “Behaviours”

All the code listed below is somehwat more verbose than the Doctrine 1 code, however much more bound to the domain of your model and very straightforward. There is no magic involved and you will fully understand what will be happening in each of the behaviours. The best of all, although not a simple trick, you will be able to combine ALL behaviours in one model class and still be completly on top of their inner workings.

Timestampable

Timestampable is a behaviour that requires you to hook into the pre-update event which is called whenever an entity is updated:

<?php
/**
 * @Id
 * @HasLifecycleCallbacks
 */
class BlogPost
{
    /**
     * @Column(type="DateTime")
     */
    private $created;

    /**
     * @Column(type="DateTime")
     */
    private $updated;

    public function __construct()
    {
        // constructor is never called by Doctrine
        $this->created = $this->updated = new DateTime("now");
    }

    /**
     * @PreUpdate
     */
    public function updated()
    {
        $this->updated = new DateTime("now");
    }
}

Sluggable

The sluggable behaviour is trivial to implement in Doctrine 2:

<?php
class BlogPost
{
    /** @Column(type="string") */
    private $slug;

    /** @Column(type="string") */
    private $title;

    public function setTitle($title)
    {
        if ($this->slug == null) {
            $this->slug = MyStringHelper::slugize($title);
        }
        $this->title = $title;
    }

    /**
     * Put this method in if your slug should be "editable"
     */
    public function setSlug($slug)
    {
        $this->slug = $slug;
    }
}

See how its much more explicit in your code how and why the slug is generated.

NestedSet

This is one of the more complex behaviours in Doctrine 1 and it won’t be necessarily more easy in Doctrine 2. However as this is an important feature we will provide an implementation as a DoctrineExtensions namespaced package that will be maintained by Doctrine Devs.

Searchable

There is currently no plan to port the Searchable behaviour to Doctrine 2, but the possibility to instantiate objects using new allows a very simple integration of a Doctrine 2 model with Apache Solr or Lucene with a little wrapper that re-creates detached instances from this powerful search engines.

For example using ezcSearch we can make our BlogPost accessible for Solr:

<?php
class BlogPost implements ezcBasePersistable, ezcSearchDefinitionProvider
{
    public function getState()
    {
        return array(
            'id' => $this->id,
            'title' => $this->title,
            'body' => $this->body,
            'slug' => $this->slug,
        );
    }

    public function setState($state)
    {
        foreach ($state AS $k => $v) {
            $this->$k = $v;
        }
    }

    static public function getDefinition()
    {
        // define search schema
        return $def;
    }
}

ezcSearch can then index a blog post whenever it is changed by hooking an EventListener into the Doctrine PreUpdate Event:

<?php
class EzcSearchListener
{
    private $_searchSession;

    public function __construct(ezcSearchSession $searchSession)
    {
        $this->_searchSession = $searchSession;
    }

    public function preUpdate(LifecycleEventArgs $args)
    {
        if ($args->getEntity() instanceof ezcBasePersistable) {
            $this->_searchSession->index($args->getEntity());
        }
    }
}

You can now hook this event into Doctrine’s EntityManager:

<?php
$searchListener = new EzcSearchListener(...);
$em->getEventManager()->addEventListener(
    array(Doctrine\ORM\Events::preUpdate), $searchListener
);

Now when you search for your entities you get returned BlogPost instances from ezcSearchs Solr interface:

<?php
// initialize a pre-configured query
$q = $session->createFindQuery( 'BlogPost' );
$searchWord = 'test';

// where either body or title contains thr $searchWord
$q->where(
    $q->lOr(
        $q->eq( 'body', $searchWord ),
        $q->eq( 'title', $searchWord )
    )
);
$searchedBlogPosts = $session->find( $q );

These instances are detached from the EntityManager when they get returned from ezcSearch and can be merged back into the persistence context:

<?php
$searchedBlogPosts[0]->setTitle("ChangeFoo");
$em->merge($searchedBlogPosts[0]);

Read about Merging, Detached instances and other cool stuff of Doctrines object model in the Working with Objects chapter of the manual.

Versionable

By default Doctrine 2 comes with a way to set a version column that is automatically incremented on each update. Using the event system it is easy to use this information to implement a versionable audit-log behaviour. The required code is more verbose than the simple configuration of Doctrine 1, however there is much less magic involved and you can implement this behaviour in a way that is trivial to understand for someone new looking at your code:

<?php
/**
 * @Entity
 * @HasLifeCycleCallbacks
 * @generatedValue(strategy="AUTO")
 */
class BlogPost
{
    /**
     * @Id
     * @Column(type="integer")
     */
    private $id;

    /**
     * @Column(type="string")
     */
    private $title;

    /**
     * @Column(type="text")
     */
    private $body;

    /**
     * @Column(type="integer")
     * @version
     */
    private $version;

    /**
     * @OneToMany(targetEntity="BlogPostVersion", mappedBy="post")
     */
    private $auditLog = array();

    /**
     * @PrePersist
     * @PreUpdate
     */
    public function logVersion()
    {
        $this->auditLog[] = new BlogPostVersion($this);
    }
    // getters
}

/**
 * @Entity
 */
class BlogPostVersion
{
    /**
     * @Id
     * @Column(type="integer")
     * @generatedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @Column(type="string")
     */
    private $title;

    /**
     * @Column(type="text")
     */
    private $body;

    /**
     * @Column(type="integer")
     */
    private $version;

    /**
     * @ManyToOne(targetEntity="BlogPost")
     */
    private $post;

    public function __construct(BlogPost $post)
    {
        $this->post = $post;
        $this->title = $post->getTitle();
        $this->body = $post->getBody();
        $this->version = $post->getCurrentVersion();
    }
}

I18N

Multi-Language content is an important topic and can be implemented in Doctrine 2, since its just a fancy name for a One-To-Many relation. However currently Doctrine 2 does not allow to persist keys by name, which makes a OneToMany implementation a bit more intensive then it could be. We plan to implement primitive value collections however which would simplify any attempt to implement nested structured content, that is not an entity by itself.

Soft Delete

We won’t support soft-delete at all. If you want to implement a soft-delete alike behaviour its probably a good idea to look into the State pattern instead.

Blameable

Implementing this behaviour is just a matter of adding two fields createdByUserId and modifiedByUserId fields and setting them whenever one of your relevant fields change by hooking into setter methods:

<?php
/**
 * @Entity
 */
class BlogPost
{
    /**
     * @Column(type="string")
     */
    private $title;

    /**
     * @Column(type="integer")
     */
    private $modifiedByUserId;

    public function updateBlogPost($title, ..., User $user)
    {
        $this->title = $title;
        $this->modifiedByUserId = $user->getId();
    }
}

Sortable

Same as I18N, we are planning to support persistence of collection keys in the Doctrine 2 Core. This would allow to sort collections by using the possibilities of the Doctrine\Common\Collections\Collection interface.

Conclusion

Although slightly more complex than Doctrine 1s simple configuration options, most “behaviours” are still way easy to implement in Doctrine 2. The additional benefit of this straightforward approach: You can combine behaviours in any way, inside your domain model, without having to wonder how the magic works together, you are completly on top of it.

]]>
Wed, 17 Feb 2010 00:00:00 +0000
http://www.doctrine-project.org/2010/02/11/database-support-doctrine2.html http://www.doctrine-project.org/2010/02/11/database-support-doctrine2.html <![CDATA[Database-Driver Support in Doctrine 2]]>

Database-Driver Support in Doctrine 2

Not only the ORM part of Doctrine will see major changes for the step from the 1.x to the Doctrine 2 series. The DBAL layer has undergone major refactorings and there has been a very throughout separation of concerns. Any database platform that will be supported has to extend four different classes/interfaces.

  • Doctrine and Doctrine - Both interfaces implement the interference between PHP and the Database, they are the lowest layer of any platform support.
  • Doctrine - This abstract class requires you to specify the specialites of the SQL dialect of the database-platform you are going to implement.
  • Doctrine - This abstract class defines the interaction of the database platform to create a database schema, for example in combination with the ORM SchemaTool.

For the Doctrine 2.0 release we plan to support 4 different platforms, all tested in-depth:

  • MySQL using the PDO Mysql extension
  • PgSQL using the PDO PostgresSQL extension
  • Oracle using the OCI extension
  • Sqlite using the PDO SQLite extension

Both the SchemaManager and Platform can be re-used for any Driver that is connected to the database. If you would want to use Mysqli instead of PDO MySQL you would only need to implement a new Driver and Statement. And if you just want to change some of the sql specific details in regard to schema generation you would only need to extend the AbstractPlatform.

Still, from a database-platform point of view the default support is lacking, for example MsSql support with both PDO and SqlSrv is currently missing. Firebird or IBM Db2 are other platforms that are wide-spread and not supported currently. However we don’t want to rush only half-finished support into Doctrine 2. That is where you come in: We would greatly appreciate any help in getting support for any new database platform into Doctrine 2.

For the implementation of a completly new database platform you can rely on the powerful PHPUnit Testsuite of Doctrine 2. There are lots of tests that check the functionality of your driver, platform and schema implementations against various scenarios. Additionally the complete ORM functional test-suite can run against your new database platform. Furthermore you can count of everyone in the Doctrine DEV Team for help, we are hanging around on Freenode IRC in the #doctrine-dev Channel. You could also create a ticket on Jira and attach a patch or just discuss your ideas.

]]>
Thu, 11 Feb 2010 00:00:00 +0000
http://www.doctrine-project.org/2010/01/22/doctrine-2-0-0-alpha4-released.html http://www.doctrine-project.org/2010/01/22/doctrine-2-0-0-alpha4-released.html <![CDATA[Doctrine 2 ALPHA4 Released]]>

Doctrine 2 ALPHA4 Released

Today we are happy to announce the release of the next, and hopefully last, alpha release of Doctrine 2. With over 60 fixed bugs and some improvements this is another significant step towards the final release.

Highlights

  • DBAL Refactorings: [DDC-169]
  • CLI Refactoring and Enhancements: [r6972] [DDC-223], [DDC-225]
  • Support for customizing the DDL of column definitions: [DDC-200]
  • XML Mapping Driver Improvements: [DDC-243], [DDC-242], [DDC-159]

View the complete change log to see a detailed list of every change contained in this release. You can download this release and report any issues you find in Jira.

We would like to thank everyone who participated in this release through bug reports, patches and suggestions.

What is Next?

We are planning to work towards entering beta from here on. There are still some backwards-incompatible changes to come. Once we hit beta, efforts will concentrate on fixing bugs and further stabilizing the code base. The first beta release is currently scheduled for March 1st, 2010.

]]>
Fri, 22 Jan 2010 00:00:00 +0000
http://www.doctrine-project.org/2009/12/07/doctrine-1-2-1-released.html http://www.doctrine-project.org/2009/12/07/doctrine-1-2-1-released.html <![CDATA[Doctrine 1.2.1 Released]]>

Doctrine 1.2.1 Released

Today we are happy to bring you the first maintenance release for the Doctrine 1.2 version. We will continue to have regular maintenance releases for the 1.2 branch for the next 18 months. On average we will have one release per month containing bug fixes only. These releases are meant to be fully backwards compatible so it is recommended that you upgrade right away!

Below are some of the changes made in this release:

  • [r6834] Fixing issue with relationship ordering

  • [r6835] Fixes issue with oracle adapter statement using wrong constant

  • [r6836] Fixing issue with sfYaml autoload not returning true

  • [r6839] Fixes issue with array cache driver and deleting

  • [r6840] Fixed thrown Exceptions to be package-level

  • [r6842] Fixes issue with $length in migrations addColumn

  • [r6859] Fixed misplaced param when parsing join condition

  • [r6883] Added empty init() method implementation to avoid method does not exist error

  • [r6889] Fixing issue with nested set createRoot() method and string root column

  • [r6893] Adding _cleanup() call to start of migrations diff to make sure directory is clean

You can view the full change log and download now! If you encounter any issues please report them in Jira.

]]>
Mon, 07 Dec 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/12/01/more-doctrine-releases.html http://www.doctrine-project.org/2009/12/01/more-doctrine-releases.html <![CDATA[More Doctrine Releases]]>

More Doctrine Releases

Only a few hours ago we released the stable version of Doctrine 1.2! Now we bring you two maintenance releases for the 1.0 and 1.1 versions of Doctrine. The number of changes in these releases are small, but they are important bug fixes. It is recommended that you upgrade. Download 1.0.14 and 1.1.6 now and report any issues you discover in Jira.

]]>
Tue, 01 Dec 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/11/30/doctrine-1-2-0-stable-released.html http://www.doctrine-project.org/2009/11/30/doctrine-1-2-0-stable-released.html <![CDATA[Doctrine 1.2.0 Stable Released]]>

Doctrine 1.2.0 Stable Released

Today I am very happy to announce that Doctrine 1.2.0 stable has been released. This is a very significant release for Doctrine as it contains a lot of valuable enhancements and bug fixes. This will most likely be the last new version of the Doctrine 1 branch that we release. This means that it is the last LTS(long term support) release as it is supported for a full 18 months. Below is the current proposed support schedule for the available Doctrine 1 versions.

| Version | Supported Until | | ———————- | ——————— | | Doctrine 1.0 | 03/01/2010 | | Doctrine 1.1 | 03/01/2010 | | Doctrine 1.2 | 06/01/2011 |

Originally 1.1 was scheduled to end support on 11/01/2009, but we have decided to support it until 03/01/2010 to give people enough time to upgrade to 1.2. After 03/01/2010 Doctrine 1.2 will be the only actively supported version of Doctrine 1.

Release Highlights

Below you will find some of the highlights from this release. Of course you can view the full upgrade page to see all the new things in Doctrine 1.2.

Please, download Doctrine 1.2 today and give it a try. Let us know any problems you have by reporting a new issue in Jira.

]]>
Mon, 30 Nov 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/11/23/new-doctrine-core-team-member.html http://www.doctrine-project.org/2009/11/23/new-doctrine-core-team-member.html <![CDATA[New Doctrine Core Team Member]]>

New Doctrine Core Team Member

Today I am very excited to announce to you all that we have officially invited Benjamin Eberlei, also known as beberlei in IRC, to join the core Doctrine team. He has steadily contributed to Doctrine 2 and has been very helpful. We are confident that he will be a great new addition to the team.

Benjamin is a contributor to the Zend Framework as well so he will be responsible for leading the integration between the projects. You can read a little more about Benjamin on his about page.

]]>
Mon, 23 Nov 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/11/23/doctrine-1-2-0-rc1-released.html http://www.doctrine-project.org/2009/11/23/doctrine-1-2-0-rc1-released.html <![CDATA[Doctrine 1.2.0-RC1 Released]]>

Doctrine 1.2.0-RC1 Released

Today the first release candidate for the 1.2 version of Doctrine is available for download. We addressed around 20 or so issues in Jira for this release and we hope to have a stable release by the end of November. Please test this latest release and report any issues you discover in Jira.

View the full change log for this release and download RC1 now!

]]>
Mon, 23 Nov 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/11/18/php-benchmarking-mythbusters.html http://www.doctrine-project.org/2009/11/18/php-benchmarking-mythbusters.html <![CDATA[PHP Benchmarking Mythbusters]]>

PHP Benchmarking Mythbusters

First of, this blog post sucks. I thought I would never write such a senseless apples and oranges comparison with artificial and meaningless benchmarks, but I was just a bit astonished by the results that I would like to share.

I use object-relational mapping tools in many different languages, from Java to C# to PHP. One of the many supposedly lightweight alternatives in PHP to Doctrine is Outlet. After stumbling upon this comment on a stackoverflow.com post: “Gotta second Outlet. Doctrine is comically bloated - it is WAY too big to be a sensible choice for anything but the lightest of server loads.” I thought I take a look at Outlet. This ORM seems to consist of only 9 classes! It can’t get any more lightweight right? I assumed it would blow Doctrine out of the water performance-wise in all situations.

So I downloaded Outlet 0.7 and created a simple test database with just 1 table. Then I wrote a small script that bootstraps Outlet, inserts 500 objects into the database and reads them out afterwards (Yes, it’s stupid, just like most other artificial benchmarks).

Environment is PHP 5.3.0 with APC.

<?php
    echo PHP_EOL . (memory_get_usage() / 1024) . ' KB ' . PHP_EOL;

include 'config.php';

set_include_path(get_include_path() . PATH_SEPARATOR . __DIR__ . '/outlet');

require 'Outlet.php';

ini_set('error_reporting', E_ALL);

class Bug
{
    public $ID;
    public $Title;
    public $Description;
}

$config = array(
  'connection' => array(
    'dsn'      => 'mysql:host=localhost;dbname=outletbenchmark',
    'username' => $mysqlUsername,
    'password' => $mysqlPassword,
    'dialect' => 'mysql'
  ),
  'classes' => array(
    'Bug' => array(
      'table' => 'bugs',
      'props' => array(
        'ID'        => array('ID', 'int', array('pk' => true, 'autoIncrement' => true)),
        'Title'     => array('Title', 'varchar'),
        'Description' => array('Description', 'varchar')
      )
    )
  )
);
Outlet::init($config);
$outlet = Outlet::getInstance();
$outlet->createProxies();

$s = microtime(true);
$outlet->getConnection()->beginTransaction();
for ($i = 0; $i < 500; ++$i) {
    $bug = new Bug;
    $bug->Title = 'This is a test bug';
    $bug->Description = 'Hey there!';

    $outlet->save($bug);
}
$outlet->getConnection()->commit();

$e = microtime(true);
echo "\nInsert:" . ($e - $s) . "\n";

$outlet->clearCache();

$s = microtime(true);
$bugs = $outlet->select('Bug');
$e = microtime(true);

$outlet->clearCache();

echo "\nQuery:" . ($e - $s) . "\n";

echo "\n" . (memory_get_usage() / 1024) . ' KB ' . PHP_EOL;

**CAUTION** First off, ini\_set('error\_reporting', E\_ALL); was
necessary to silence the following E\_STRICT warnings coming from
Outlet:

::

    Strict Standards: Non-static method OutletMapper::get() should not be called statically,
    assuming $this from incompatible context in /Users/robo/dev/php/outlet/outlet-0.7/classes
    /outlet/Outlet.php on line 184

    Strict Standards: Only variables should be passed by reference in /Users/robo/dev
    /php/outlet/outlet-0.7/classes/outlet/OutletMapper.php on line 546

Does not really look good (and does not speak for Outlet very
well), but anyway.

I did the same for Doctrine 2.0, without setting up a metadata or query cache.

<?php
echo PHP_EOL . (memory_get_usage() / 1024) . ' KB ' . PHP_EOL;

include 'config.php';

require 'doctrine/Doctrine/Common/IsolatedClassLoader.php';

/**
 * @Entity
 * @Table(name="bugs")
 */
class Bug
{
    /** @Id @Column(type="integer") @GeneratedValue(strategy="AUTO") */
    public $ID;
    /** @Column(type="string") */
    public $Title;
    /** @Column(type="string") */
    public $Description;
}

$classLoader = new \Doctrine\Common\IsolatedClassLoader('Doctrine');
$classLoader->setBasePath(__DIR__ . '/doctrine');
$classLoader->register();

$config = new \Doctrine\ORM\Configuration;

$config->setProxyDir(__DIR__ . '/Proxies');
$config->setProxyNamespace('Proxies');
$connectionOptions = array(
    'driver' => 'pdo_mysql',
    'user' => $mysqlUsername,
    'password' => $mysqlPassword,
    'host' => 'localhost',
    'dbname' => 'doctrine2benchmark'
);

$em = \Doctrine\ORM\EntityManager::create($connectionOptions, $config);

$s = microtime(true);
for ($i = 0; $i < 500; ++$i) {
    $bug = new Bug;
    $bug->Title = 'BBug';
    $bug->Description = 'Hello there!';

    $em->persist($bug);
}
$em->flush();

$e = microtime(true);
echo "\nInsert:" . ($e - $s) . "\n";

$em->clear();

$s = microtime(true);
$bugs = $em->getRepository('Bug')->findAll();
$e = microtime(true);

$em->clear();

echo "\nQuery:" . ($e - $s) . "\n";

echo "\n" . (memory_get_usage() / 1024) . ' KB ' . PHP_EOL;

Here are my results.

1st Run

| Measurement | | Outlet | | Doctrine | | ———— | | —————– | | ——————- | | Insert Time | | 0.23142600059509 | | 0.11601996421814 | | Query Time | | 0.070523977279663 | | 0.025638818740845 | | Used Memory | | 644.5546875 KB | | 1061.83203125 KB |

No, I did not swap the numbers, I promise. You see that the D2 version uses about 400KB more memory but the result of the timings are quite surprising. Being curious I ran both scripts several times which means the query section has to hydrate 500 objects more for each run.

2nd Run

1st refresh (1000 objects)

| Measurement | | Outlet | | Doctrine | | ———— | | —————– | | ——————- | | Insert Time | | 0.26595592498779 | | 0.11661005020142 | | Query Time | | 0.14437794685364 | | 0.052286863327026 | | Used Memory | | 875.0703125 KB | | 1313.15625 KB |

3rd Run

2nd refresh (1500 objects)

| Measurement | | Outlet | | Doctrine | | ———— | | —————– | | ——————- | | Insert Time | | 0.2314441204071 | | 0.11621117591858 | | Query Time | | 0.21359491348267 | | 0.079329013824463 | | Used Memory | | 1139.5859375 KB | | 1541.59375 KB |

Did you expect these results? After all Doctrine is so bloated, right? (Doctrine 2 full package ~250 classes) and Outlet is so lightweight (~9 classes)?

Bottom line:

  • The number of classes barely means anything. (Its probably a good criterion if you’re short on disk space).
  • “Lightweight” is a buzzword and meaningless without a reference point.
  • Don’t judge a library by its size and certainly dont try to draw conclusions from the size to the performance, or worse to the scalability. It just doesnt work.
  • Artificial benchmarks suck.
  • To all the folks hunting for everything lightweight and micro-benchmarking all day long: You’re wasting your time (Just like I did with this stupid benchmark...).
  • Don’t trust artificial benchmarks (Not even this one).

PS: This is no post against Outlet, so if any Outlet guys or fans are reading this, please don’t feel offended. Since I dont know Outlet well I’m sure I did a lot of things wrong but thats really not important here. I am just making a stance against all the ridiculously stupid artificial benchmarks out there that try to make people believe Doctrine is slow and bloated. This post shows I can make it look the other way around easily. That just shows how meaningless these comparisons are.

NOTE All the code used to run these benchmarks can be downloaded from here. It is a zip archive containing all the code you need to run the benchmarks yourself.
]]>
Wed, 18 Nov 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/11/16/doctrine-1-2-0-beta3-released.html http://www.doctrine-project.org/2009/11/16/doctrine-1-2-0-beta3-released.html <![CDATA[Doctrine 1.2.0 BETA3 Released]]>

Doctrine 1.2.0 BETA3 Released

We’re getting very close to a stable Doctrine 1.2 with the latest BETA3 being released today. This will most likely be the last beta release before our first release candidate next week. If everything goes as planned we will have a stable release hopefully a little before the end of November.

You can view the change log or download this release now. If you find any issues please open tickets in Jira.

]]>
Mon, 16 Nov 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/11/11/doctrine-2-0-0-alpha3-released.html http://www.doctrine-project.org/2009/11/11/doctrine-2-0-0-alpha3-released.html <![CDATA[Doctrine 2.0.0-ALPHA3 Released]]>

Doctrine 2.0.0-ALPHA3 Released

Today I am happy to bring you the third alpha version of Doctrine 2! This release contains over 60 fixes and the code is starting to stabilize.

Highlights

  • [r6441] Added functionality to convert a Doctrine 1 schema to Doctrine 2 to help users with upgrading.
  • [r6442] Work on mapping drivers, exporter drivers and reverse engineering of database schemas.
  • [r6551] Refactorings to reduce duplicated code and increase efficiency.
  • [r6554] Refactored cache drivers to allow more control over deleting, added namespacing to cache drivers and implemented clear-cache task.

View the complete change log to see a detailed list of every change contained in this release. You can download this release and report any issues you find in Jira.

What is Next?

We will have one more alpha release on December 11th, 2009 and our first beta on January 8th, 2010. The schedule after that has not yet been determined.

]]>
Wed, 11 Nov 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/11/10/doctrine-1-2-0-beta2-released.html http://www.doctrine-project.org/2009/11/10/doctrine-1-2-0-beta2-released.html <![CDATA[Doctrine 1.2.0-BETA2 Released]]>

Doctrine 1.2.0-BETA2 Released

Today I am happy to bring you the second beta of the latest Doctrine 1.2 version. This is a solid bug fix release and we’re getting very close to a stable 1.2 version of Doctrine! It is recommended that you upgrade and report any issues in Jira to help us test for regressions between 1.1 and 1.2.

Take a look at the changelog and try it out by downloading it.

]]>
Tue, 10 Nov 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/11/04/doctrine-1-2-documentation-available.html http://www.doctrine-project.org/2009/11/04/doctrine-1-2-documentation-available.html <![CDATA[Doctrine 1.2 Documentation Available]]>

Doctrine 1.2 Documentation Available

I am happy to announce that Doctrine 1.2 documentation is now available and up to date. It might still need some work but for the most part it is updated with all the new features and changes in 1.2.

New Chapters

Please read over it and create Jira issues for any problems or corrections you find.

]]>
Wed, 04 Nov 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/11/03/a-doctrine-triple-play.html http://www.doctrine-project.org/2009/11/03/a-doctrine-triple-play.html <![CDATA[A Doctrine Triple Play]]>

A Doctrine Triple Play

Today I am happy to bring you three new versions of Doctrine:

Doctrine 1.0.13

This is a regular maintenance release for the Doctrine 1.0 branch and contains several bug fixes. Check out the change log for the changes contained in this release.

Doctrine 1.1.5

This is a regular maintenance release for the Doctrine 1.1 branch. This will be the one of the last maintenance release for the Doctrine 1.1 branch as the scheduled support for this version has technically ended on November 1st. We will have a few more maintenance releases for 1.1 since Doctrine 1.2 is not out yet. We’ll give a few months of overlap to give people some time to upgrade to Doctrine 1.2. Check out the change log for the changes contained in this release.

Doctrine 1.2.0-BETA1

This is the first BETA of the Doctrine 1.2 branch. This release is a very exciting one as it will be a LTS(long term support) version and it contains lots of new features and bug fixes. Check out the change log for the changes contained in this release. You can also see documentation for everything that has changed or is new in Doctrine 1.2 on the What’s New page.

Like always, you can grab the package for these new versions on the download page.

]]>
Tue, 03 Nov 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/10/21/doctrine-1-2-alpha3-released.html http://www.doctrine-project.org/2009/10/21/doctrine-1-2-alpha3-released.html <![CDATA[Doctrine 1.2 ALPHA3 Released]]>

Doctrine 1.2 ALPHA3 Released

Today I am happy to bring you hopefully the last alpha release for Doctrine 1.2. We decided to have one more alpha due to some interesting issues and improvements brought to our attention related to PEAR model/file naming standards, result set caching improvements and a few other things. You can of course check out what all is new in Doctrine in the upgrade file. Below are some quick links to some of the most recent changes.

Go ahead and download Doctrine 1.2 ALPHA3 and give it a try. Let us know if you have any issues by raising a new issue in JIRA.

]]>
Wed, 21 Oct 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/10/07/doctrine-2-documentation.html http://www.doctrine-project.org/2009/10/07/doctrine-2-documentation.html <![CDATA[Doctrine 2 Documentation]]>

Doctrine 2 Documentation

Did you know that Doctrine 2 is already very well documented? I’ve noticed recently that some people seem to think we don’t have any documentation for it, and that upgrading will not be possible for many months to come.

We have an almost complete manual on Doctrine 2 which is the same concept of “Guide to Doctrine for PHP” for Doctrine 1. It covers all the core concepts of Doctrine 2 as well as information on how to get started, code examples, best practices, etc.

The Guide to Doctrine for PHP starts off with the following chapters...

The following chapters have been completed and updated recently...

We also have a cookbook with a few articles already too...

We hope this helps you a little bit with getting started using Doctrine 2 and that you enjoy it! :)

]]>
Wed, 07 Oct 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/10/06/doctrine-1-2-nearing-stable-release.html http://www.doctrine-project.org/2009/10/06/doctrine-1-2-nearing-stable-release.html <![CDATA[Doctrine 1.2 Nearing Stable Release]]>

Doctrine 1.2 Nearing Stable Release

Today I am happy to release to you the second ALPHA release of Doctrine 1.2. Honestly, we didn’t receive many reports of regressions or problems with the new things in Doctrine 1.2 and we know lots of people have upgraded and using it so we feel it is a pretty stable release already.

You can view what all changed in this release by checking the changelog and you can snag it from the download page.

We hope that everything goes fine from here and the next release will be BETA1 followed by an RC and stable release. Please give 1.2 a try and report any regressions to us so that we can be sure to get them fixed before the final stable release.

]]>
Tue, 06 Oct 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/10/05/second-alpha-release-of-doctrine-2.html http://www.doctrine-project.org/2009/10/05/second-alpha-release-of-doctrine-2.html <![CDATA[Second Alpha Release of Doctrine 2]]>

Second Alpha Release of Doctrine 2

Today we are happy to bring you the second alpha release of the brand new Doctrine 2! This release contains about 70 fixes since the first alpha release last month! This is great news as it means Doctrine 2 is becoming more and more stable!

Highlights

Below are some highlights for the release.

  • CLI refactorings and improvements
  • Fixes to Mapping information drivers
  • Fixes to ClassMetadata export drivers
  • Lots of other bug fixes

If you’re curious about what all was committed in this release you can check the change log page and you can snag the packages from the download page.

]]>
Mon, 05 Oct 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/10/02/doctrine-fedora-package.html http://www.doctrine-project.org/2009/10/02/doctrine-fedora-package.html <![CDATA[Doctrine Fedora Package]]>

Doctrine Fedora Package

Thanks to Christof Damian, a loyal Doctrine user, if you are a Fedora user you can now yum install the latest stable version of Doctrine. Below is what you can run from the command line to get it!

yum install php-doctrine-Doctrine

Enjoy and let us know if you have any issues. Thanks

]]>
Fri, 02 Oct 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/09/25/doctrine-1-0-12-and-1-1-4-released.html http://www.doctrine-project.org/2009/09/25/doctrine-1-0-12-and-1-1-4-released.html <![CDATA[Doctrine 1.0.12 and 1.1.4 Released]]>

Doctrine 1.0.12 and 1.1.4 Released

Today I am happy to bring you two new maintenance releases for the 1.0 and 1.1 versions of Doctrine. These are both standard maintenance releases and only contain bug fixes.

NOTE 1.1 End of Life

This is the second to last maintenance release for the 1.1 version and we are still scheduled to hit the end of life on November 1, 2009. The good news is 1.2 will be a LTS(long term support) release and will have 18 months of support from the date it is released.

You can view the change logs and download these releases on the download page.

]]>
Fri, 25 Sep 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/09/18/doctrine-1-2-0-alpha-released.html http://www.doctrine-project.org/2009/09/18/doctrine-1-2-0-alpha-released.html <![CDATA[Doctrine 1.2.0-ALPHA Released]]>

Doctrine 1.2.0-ALPHA Released

Today I am happy to announce the immediate availability of Doctrine 1.2.0 ALPHA1. As you all may already know, 1.2 will most likely be the last 1.x version and is a LTS(long term support) release. We will post the official support schedule once 1.2 is stable and released.

You can download Doctrine 1.2.0-ALPHA1 on the download page just like normal.

This release contains many changes, bug fixes and enhancements. Some of them are highlighted below.

  • Removed string support from attributes system for performance increase
  • Cleaned up and removed deprecated code
  • Added ability to configure base Table, Query and Collection classes
  • Added ability to register custom hydrator and connection drivers
  • Enhanced Table magic finders to include conditions
  • Introduced Doctrine Extensions Repository
  • On Demand Hydration for better performance and less memory usage
  • Other various bug fixes, convenience enhancements and other minor performance improvements

You can view the full details of all the changes in the upgrade file. We use this to document all major changes so that upgrading is easier for you.

]]>
Fri, 18 Sep 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/09/14/moving-to-jira.html http://www.doctrine-project.org/2009/09/14/moving-to-jira.html <![CDATA[Moving to JIRA]]>

Moving to JIRA

While we really like Trac, especially its subversion integration, it has a lot of shortcomings for bigger projects in the area of project & issue/ticket management. Hence we decided to evaluate alternatives and ended up with choosing JIRA. Its normally not free software but the generous guys from Atlassian granted us a free open source license. A big thanks from all of us to Atlassian for their support of open source projects.

From now on all the project management, release management and issue/ticket management will happen in our new JIRA instance. While it is open for everyone in read-only mode, we strongly encourage you to create an account soon so that you can create/modify/comment issues and content in JIRA.

Trac is from now on closed for tickets. All new tickets need to be reported through JIRA. We are not going to automatically import all tickets from Trac to JIRA because that does not work very well and would require to import all user accounts as well, which can not be done easily either. We will continue to work on the “old” tickets, always starting with porting a ticket over to JIRA before working on it. If you want to help, you recreate tickets that are especially important to you in JIRA yourself. You can still log in to Trac and view tickets for the purpose of migrating them to JIRA but you can not modify them or create new ones.

CAUTION When you recreate an issue in JIRA, please make sure you close the issue in Trac with the resolution: “migrated”.

Trac will not be completely shut down, however. The following functionality will stay open:

  • Wiki
  • Timeline
  • Browse Source

That is, the wiki and the subversion integration. We basically use Trac as the subversion viewer that we coupled with JIRA. Any changeset numbers or file references in JIRA issues will link to the changesets/sources in Trac.

We’re looking forward to working with JIRA and we think it is an improvement for all users. We hope you enjoy all the new functionality provided by JIRA, like voting for issues that are important to you, tracking issues and much more.

So, head over to our JIRA instance , create an account and start creating issues and explore the features.

]]>
Mon, 14 Sep 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/09/01/doctrine2-preview-release.html http://www.doctrine-project.org/2009/09/01/doctrine2-preview-release.html <![CDATA[Doctrine 2 Preview Release]]>

Doctrine 2 Preview Release

Exactly one year ago today we released Doctrine 1.0 stable, which was on the birthday of Jon. Again, today we have chosen the birthday of Jon to release the first preview of Doctrine 2. This is an alpha release that is not intended for production use.

Doctrine 2 marks the beginning of a new approach to ORM with Doctrine. It represents a rewrite of more than 90% of the existing codebase. The new key concepts behind Doctrine 2 are to put your domain model more into focus and to provide transparent persistence where the persistence is a service and not an inherent property of domain classes. This has a lot of advantages like decoupling your valuable business logic from the persistence layer and easy testability of your domain model.

Packages

Doctrine 2 is reorganized into reusable layers that are available as separate packages. The Doctrine 2 Core consists of the following packages:

  • Doctrine Common (Generic components, high re usability)
  • Doctrine DBAL (The database abstraction layer, includes: Common)
  • Doctrine ORM (The ORM tools, includes: Common + DBAL)

All of these packages are currently distributed and maintained synchronously which means they are released together and share the same version numbers. This may change in the future. These three packages are available as separate downloads even though you will most likely want to download the ORM package which already contains the Common and DBAL packages.

Features

This Preview Release is mainly about the core ORM functionality and features of Doctrine 2, like mapping drivers, DQL, association mapping, inheritance mapping, change tracking, etc. Most of the supporting tools that you are used to for rapid development like the CLI, migrations, behaviors and validation have not yet been ported to Doctrine 2 and are still under heavy development, most of them will end up as loosely coupled extensions.

Mapping drivers

A mapping driver is a particular strategy for providing ORM metadata to Doctrine 2. This Preview Release contains mapping drivers for docblock annotations, XML and YAML. The XML and YAML drivers are still in an experimental stage and while we encourage you to use them, you may encounter more issues than with the docblock annotation driver as it is the primary driver used in our development.

Documentation

The documentation for Doctrine 2 can be found here. Please be aware that the documentation is still a work in progress and not all areas have been completed.

Sandbox

To get started quickly, please check out our sandbox quickstart tutorial. You can also obtain Doctrine 2.0.0 ALPHA1 via a PEAR package like normal which can be found on the download

We want to encourage everyone to start experimenting with the new generation of Doctrine in order to get familiar with it and to help find any outstanding issues.

As always, please report any issues and feature requests through trac.

Thank you for using Doctrine.

]]>
Tue, 01 Sep 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/08/24/doctrine-2-0-quality-assurance.html http://www.doctrine-project.org/2009/08/24/doctrine-2-0-quality-assurance.html <![CDATA[Doctrine 2.0 Quality Assurance]]>

Doctrine 2.0 Quality Assurance

Greetings folks!

Today I’d like to talk about Quality Assurance in PHP projects. Currently, PHP lacks good tools for QA, but thanks to a special PHP user, Sebastian Bergmann , this is changing gradually. If you don’t know him, you can visit his blog and check about projects he’s on. For lazy people, he’s the author of PHPUnit , a de-facto Unit Test suite in PHP.

Doctrine 2.0 uses PHPUnit as our Unit Test suite. It relies on PEAR to be installed, but you can also install it via SVN.

The main initiative of QA in PHP projects is the website http://qualityassuranceinphpprojects.com. There you can find available tools to measure, for example, how complex is your project and possible semantical issues.

I have applied some of these tests against Doctrine 2.0 to see how complex it is and if it can be optimized more. The first test I run is a trace about how complex our code base is. The tool I used is phploc. Check out the results:

[bash]
MacBlanco:bin guilhermeblanco$ ./phploc /Users/guilhermeblanco/www/doctrine/trunk/lib
phploc 1.1.1 by Sebastian Bergmann.

Directories:                               31
Files:                                    210

Lines of Code (LOC):                    38826
Comment Lines of Code (CLOC):           17004
Non-Comment Lines of Code (NCLOC):      21822

Interfaces:                                11
Classes:                                  229
Non-Static Methods:                      1699
Static Methods:                           106
Functions:                                 95

Of course it still misses a couple of code to implement (CLI Tasks, Locking strategies, ID Generators), but now we know how big Doctrine 2.0 is. Then, I decided to check duplicated code (possible optimization locations). The tool phpcpd gave me this feedback:

[bash]
MacBlanco:bin guilhermeblanco$ ./phpcpd /Users/guilhermeblanco/www/doctrine/trunk/lib
phpcpd 1.1.1 by Sebastian Bergmann.

Found 1 exact clones with 15 duplicated lines in 2 files:

  - ./Doctrine/DBAL/Platforms/MsSqlPlatform.php:126-141
    ./Doctrine/DBAL/Platforms/MySqlPlatform.php:633-648

0.04% duplicated lines out of 38826 total lines of code.

I asked myself: It must be a method that could be moved to AbstractPlatform.php! So I opened both files and... no! It’s a piece of code that cannot be optimized. So, consider Doctrine 2.0 extremely optimized, because there is no duplicated code internally!

Now Unit Test suite. Doctrine 2.0 has a steadily growing set of Unit Tests, and we are regularly analyzing the code coverage analysis to find parts that need more tests. Here is how such a coverage report is generated:

[bash]
MacBlanco:tests guilhermeblanco$ phpunit --coverage-html=./_coverage Doctrine_Tests_AllTests
PHPUnit 3.3.17 by Sebastian Bergmann.

.....................................S.S....................  60 / 562
............................................................ 120 / 562
.....................................................SSSSSSS 180 / 562
SSSSSSSSSSSSSSSS............................................ 240 / 562
............................................................ 300 / 562
............................................................ 360 / 562
............................................................ 420 / 562
............................................................ 480 / 562
............................................................ 540 / 562
...SS.................

Time: 18 seconds

OK, but incomplete or skipped tests!
Tests: 562, Assertions: 1420, Skipped: 27.

Generating code coverage report, this may take a moment.

The generated coverage can be seen in the following picture.

Finally, some metrics are good to inspect how stable is our code. I applied pdepend , and it gave me these results:

jdepend chart

jdepend chart

pyramid overview

pyramid overview

The command I ran was:

[bash]
MacBlanco:bin guilhermeblanco$ ./pdepend --summary-xml=/Users/guilhermeblanco/summary.xml --jdepend-chart=/Users/guilhermeblanco/jdepend.svg --overview-pyramid=/Users/guilhermeblanco/pyramid.svg /Users/guilhermeblanco/www/doctrine/trunk/lib

Here is the generated summary. If you have any other ideas/tools that we should apply in our codebase to generate other metrics, please drop us a message!

]]>
Mon, 24 Aug 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/08/22/transactions-and-performance.html http://www.doctrine-project.org/2009/08/22/transactions-and-performance.html <![CDATA[Transactions and Performance]]>

Transactions and Performance

In this post I want to clarify some things about transactions and performance of PHP applications in general. I want to show you that it is very easy to lose a lot of performance without using any “heavy” framework at all and I also want to show that frameworks can actually help you avoid a lot of these problems transparently. I want to sensibilize you for the fact that there are a lot of factors in PHP application performance and that you can very easily lose the performance that you hoped to gain by not using framework X or Z or building your own (“Not Invented Here”-syndrome) by several orders of magnitude through rather trivial errors or misconceptions.

Given a MySql database with InnoDB tables, which of the following code snippets that insert 20 users do you think is faster? First the Doctrine (2) version:

<?php
// Using Doctrine 2 to insert 20 users
for ($i=0; $i<20; ++$i) {
    $user = new CmsUser;
    $user->name = 'Guilherme';
    $user->status = 'Slave';
    $user->username = 'gblanco';
    $em->persist($user);
}

$s = microtime(true);
$em->flush();
$e = microtime(true);
echo ($e - $s) . "<br/>";

Now the good old mysql_query version:

<?php
$s = microtime(true);
for ($i=0; $i<20; ++$i) {
    mysql_query("INSERT INTO cms_users (name, status, username) VALUES ('Guilherme', 'Slave', 'gblanco')", $link);
}
$e = microtime(true);
echo ($e - $s) . "<br/>";

Even this comparison is not fair since flush() is doing a lot more stuff but anyhow. The results might surprise some of you:

Doctrine 2: 0.0094 seconds
mysql_query: 0.0165 seconds

Yes, our good old mysql_query code is almost twice as slow even though it does a lot less, provides no features, no abstraction, no basic protection against SQL injection, etc. Why is that? The answer is: transactions. In the Doctrine 2 example, Doctrine takes over transaction management for us and efficiently executes all inserts in a single, short transaction. In the plain mysql_query example, there is no transaction demarcation and since MySql by default operates in autocommit mode, every mysql_query call will implicitly commit the transaction and start a new one. Thats 20 transactions. Here is the revised code of the second example with proper transaction demarcation:

<?php
$s = microtime(true);
mysql_query('START TRANSACTION', $link);
for ($i=0; $i<20; ++$i) {
    mysql_query("INSERT INTO cms_users (name, status, username) VALUES ('Guilherme', 'Slave', 'gblanco')", $link);
}
mysql_query('COMMIT', $link);
$e = microtime(true);
echo ($e - $s) . "<br/>";

The result:

mysql_query: 0.0028 seconds

Thats a huge difference. We can conclude:

Bad or no transaction management/demarcation can reduce performance by several orders of magnitude.

Many people are used to autocommit mode without really being aware of what it is doing. It does not mean there is no transaction unless you issue START/BEGIN TRANSACTION or PDO#beginTransaction(). It means after every single query a transaction is committed automatically and a new one started. Methods like PDO#beginTransaction() merely suspend autocommit mode for a short duration (until you call PDO#commit()/PDO#rollback()).

To clarify:

You can not talk to your database outside of a transaction.

Even SELECT queries get wrapped in a small transaction in autocommit mode. However since SELECT statements usually don’t result in any write locks (like INSERT/UPDATE/DELETE) the penalty of these transactions is usually not that big.

Doctrine 2 can help a lot here. You can modify your objects anywhere, persist and delete objects anywhere and once you call EntityManager#flush() Doctrine 2 will efficiently make all updates in a single transaction.

What I wanted to highlight with this post is that there are a lot of factors that influence the performance of your application, and raw execution speed of the code is certainly not one of the most influential ones. You can very easily lose 10 times the performance by trivial things such as the one shown above (bad/no transaction demarcation) than what you gained by choosing some “ultra lightweight” PHP framework or a homegrown solution.

There are many more factors, like network load, inefficient database indices or no indices, and much more. Don’t just always look at the raw execution speed of your code. Use code that is well tested, established, used by lots of people and developed by lots of people. Don’t reinvent the wheel and use existing tools or help make existing tools better! (Oh, and use the right tool for the job, of course!)

Most of the time when you think your own solutions are much better and have a lot less bugs than existing ones then thats most likely just because noone else is using it and so the bugs are never found :-).

PS: If you’re still confused by the autocommit mode, let me recommend this excellent page from the Hibernate project: Non-transactional data access and the auto-commit mode

]]>
Sat, 22 Aug 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/08/15/doctrine2-native-queries.html http://www.doctrine-project.org/2009/08/15/doctrine2-native-queries.html <![CDATA[Doctrine 2 Native Queries]]>

Doctrine 2 Native Queries

If you are familar with Doctrine_RawSql from Doctrine 1.x you probably know that it is somewhat broken by design since it requires a special syntax in the select clause that makes a lot of SQL constructs in the select clause impossible.

Doctrine 2 introduces a facility called “native queries”, represented by the Doctrine\ORM\NativeQuery class that replaces Doctrine_RawSql. The clue about NativeQuery is that it allows the usage of real native SQL yet the result can be transformed into all the different formats that are supported by DQL.

This is achieved through having a generic description of how an SQL result maps to a Doctrine result in form of a Doctrine\ORM\Query\ResultSetMapping.

Enough of the introductory talk, lets look at a (primitive) example from our test suite:

<?php
$rsm = new ResultSetMapping;
$rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u');
$rsm->addFieldResult('u', 'id', 'id'); // ($alias, $columnName, $fieldName)
$rsm->addFieldResult('u', 'name', 'name'); // // ($alias, $columnName, $fieldName)

$query = $this->_em->createNativeQuery('SELECT id, name FROM cms_users WHERE username = ?', $rsm);
$query->setParameter(1, 'romanb');

$users = $query->getResult();

$this->assertEquals(1, count($users));
$this->assertTrue($users[0] instanceof CmsUser);
$this->assertEquals('Roman', $users[0]->getName());

The SQL that is passed to createNativeQuery is not touched by Doctrine in any way. The NativeQuery and ResultSetMapping combination are extremely powerful. It might not surprise you that Doctrine 2 creates a ResultSetMapping internally when it transforms DQL to SQL.

Granted, this was a very trivial example that can easily be expressed in a short DQL 1-liner but it was just for demonstration purposes (and I am bad at making up complex ad-hoc SQL examples that make sense).

So when is this useful? While DQL has been heavily improved in Doctrine 2 and has many new powerful features which we will cover in future blog posts, it is sometimes necessary to use native SQL. NativeQuery gives you the ability to do that while still retrieving the results in the convenient Doctrine formats you are familar with. NativeQuery is also an obvious choice when starting to migrate a pure SQL project to Doctrine without going into all the DQL details from the start.

More on NativeQuery and ResultSetMapping can be found in the new documentation under:

Documentation - Native Sql

]]>
Sat, 15 Aug 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/08/07/doctrine2-batch-processing.html http://www.doctrine-project.org/2009/08/07/doctrine2-batch-processing.html <![CDATA[Doctrine 2 Batch Processing]]>

Doctrine 2 Batch Processing

TIP Disclaimer: In general, an ORM is surely not the best tool for the job for mass data movements, however, it can be a convenient alternative if the performance is sufficient. Every RDBMS has its own highly efficient commands for such operations. For maximum efficiency you should consult the manual of your RDBMS.

NOTE The hardware used for the following tests: MBP, Intel Core 2 Duo 2.53 Ghz, 4GB DDR3 RAM, 7200rpm HDD.

A lot of people have encountered the infamous “memory exhausted” errors when using Doctrine for bulk operations or in long-running scripts. This is a problem that is the result of 2 things:

  • The often unnecessarily intertwined architecture of Doctrine 1.x.

  • The simple garbage collector of PHP < 5.3.

    NOTE If you did not know it yet, basically every circular reference between objects (and that is every bidirectional relationship!) is a potential memory leak in PHP < 5.3.

Now, the PHP team did their homework and introduced a new garbage collector in PHP 5.3 (that is enabled by default, thank god!) that is capable of properly detecting cyclic references that are not referenced any longer from the outside.

In Doctrine 2 we did our part of the homework to address this issue and redesigned the Doctrine core from scratch. The result is a much better user experience, as I will demonstrate with some examples.

Mass inserts

The first thing we will look at is mass inserts. In Doctrine 2 there is a special pattern that can be used for mass inserts that looks as follows:

<?php
// $em instanceof EntityManager
$batchSize = 20;
for ($i=1; $i<=10000; ++$i) {
     $obj = new MyEntity;
     $obj->setFoo('...');
     // ... set more data
     $em->persist($obj);
     if (($i % $batchSize) == 0) {
         $em->flush();
         $em->clear();
    }
}

I used this pattern to create a little demonstration that looks like this in a PHPUnit test:

<?php
// $this->_em created in setUp()
echo "Memory usage before: " . (memory_get_usage() / 1024) . " KB" . PHP_EOL;
$s = microtime(true);
$batchSize = 20;
for ($i=1; $i<=10000; ++$i) {
     $user = new CmsUser;
     $user->status = 'user';
     $user->username = 'user' . $i;
     $user->name = 'Mr.Smith-' . $i;
     $this->_em->persist($user);
     if (($i % $batchSize) == 0) {
         $this->_em->flush();
         $this->_em->clear();
    }
}

//gc_collect_cycles(); // explained later!
echo "Memory usage after: " . (memory_get_usage() / 1024) . " KB" . PHP_EOL;

$e = microtime(true);
echo ' Inserted 10000 objects in ' . ($e - $s) . ' seconds' . PHP_EOL;

As you can see, we insert a total of 10000 objects. On running this code through PHPUnit, using an SQLite in-memory database, I got the following output:

Memory usage before: 5034.03515625 KB
Memory usage after: 6726.3515625 KB
Inserted 10000 objects in 3.165983915329 seconds

We can see the following:

  • The insertion of 10000 objects through Doctrine into an SQLite in-memory database took roughly 3 seconds, not too bad.
  • Memory usage increased by roughly 1.7MB, not too bad either.

If you are now still not satisfied and wonder where the 1.7MB are going, here is the answer: A small part of that is occupied by objects that were created on-demand internally by Doctrine, these will stay pretty constant, however. But the majority of this 1.7MB has simply not yet been reclaimed (but is eliglible for garbage collection for the new garbage collector!). To prove that, I can just uncomment the gc_collect_cycles() function call. Here’s the result:

Memory usage before: 5034.3828125 KB
Memory usage after: 5502.21484375 KB
Inserted 10000 objects in 3.1807188987732 seconds

Much better! And to prove that the ~500KB occupied by Doctrine are constant, I simply made it 20000 objects. Here is the result:

Memory usage before: 5034.3828125 KB
Memory usage after: 5502.21484375 KB
Inserted 20000 objects in 6.6149919033051 seconds

We can see the following things:

  • Memory usage is constant, the second batch of 10000 objects did not result in additional memory usage.
  • The mass insertion strategy scales almost linearly. 10k objects took ~3.2 seconds and 20k objects took ~6.6 seconds.

Note: You do not really need to call gc_collect_cycles(). This should just demonstrate that the memory can be reclaimed. PHP would reclaim that memory anyway when it needs to.

Even better, when testing the peak memory usage (memory_get_peak_usage()) it turned out that the memory usage never grew beyond ~10MB in between. If you choose a larger batch size the peak memory usage will be higher and vice versa.

Mass object processing

Now we take a look at mass-processing objects, which means loading 10000 objects from the database and doing something with each of them. The clue here is the new support for iterative (step-by-step) hydration in Doctrine 2. The pattern for these kinds of tasks looks as follows:

<?php
$q = $this->_em->createQuery("<DQL to select the objects I want>");
$iterableResult = $q->iterate();
while (($row = $iterableResult->next()) !== false) {
        // do stuff with the data in the row, $row[0] is always the object
        $this->_em->detach($row[0]); // detach from Doctrine, so that it can be GC'd immediately
 }

So instead of using $q->execute() or $q->getResult() or similar, we use $q->iterate() which returns an instance of IterableResult that allows us to iterate over the result step by step. The important part for not running out of memory is the line where the created object is detached from Doctrine, which results in Doctrine removing any internal references to that object, Doctrine no longer “knows” about that object.

I used this pattern to iterate through the just inserted 10000 objects as follows:

<?php
$q = $this->_em->createQuery("select u from Doctrine\Tests\Models\CMS\CmsUser u");
$iterableResult = $q->iterate();

echo "Memory usage before: " . (memory_get_usage() / 1024) . " KB" . PHP_EOL;

while (($row = $iterableResult->next()) !== false) {
    // ... I could do some stuff here
    $this->_em->detach($row[0]);
}

echo "Memory usage after: " . (memory_get_usage() / 1024) . " KB" . PHP_EOL;

The following is the result:

Memory usage before: 6578.58984375 KB
Memory usage after: 6581.71875 KB

The result is pretty acceptable. Here is the same again, this time for 20000 objects, again to prove that the small memory increase is constant:

Memory usage before: 6578.23828125 KB
Memory usage after: 6581.359375 KB

Good stuff!

NOTE If you’re thinking that I waited ages until the 10k or 20k objects were hydrated, that was not the case. 10k or 20k objects (without associations) are hydrated in seconds.

More information on bulk operations with Doctrine 2 can be found in the (very new) online manual that is still a work in progress:

http://www.doctrine-project.org/documentation/manual/2_0/en/batch-processing

UPDATE

Some people seem to be wondering why Doctrine does not use multi-inserts (insert into (...) values (...), (...), (...), ...

First of all, this syntax is only supported on mysql and newer postgresql versions. Secondly, there is no easy way to get hold of all the generated identifiers in such a multi-insert when using AUTO_INCREMENT or SERIAL and an ORM needs the identifiers for identity management of the objects. Lastly, insert performance is rarely the bottleneck of an ORM. Normal inserts are more than fast enough for most situations and if you really want to do fast bulk inserts, then a multi-insert is not the best way anyway, i.e. Postgres COPY or Mysql LOAD DATA INFILE are several orders of magnitude faster.

These are the reasons why it is not worth the effort to implement an abstraction that performs multi-inserts on mysql and postgresql in an ORM.

I hope that clears up some questionmarks.

]]>
Fri, 07 Aug 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/08/04/help-write-tests-for-new-dql-parser.html http://www.doctrine-project.org/2009/08/04/help-write-tests-for-new-dql-parser.html <![CDATA[Help write tests for new DQL Parser]]>

Help write tests for new DQL Parser

As you all know, we’re focusing most of our development time on Doctrine 2.0 these days. To help speed things up, we would like to ask for help writing tests from our users

Recently I finished new DQL parser for 2.0. Most of you may not be familiar with compiler’s theory, but for those that are, it’s a top-down recursive descent parser for a context-free grammar, usually known as LL(k).

We mapped the entire supported DQL into a document, which is an EBNF (Extended Backus-Naur Form) , which is a meta-syntax notation to express context-free grammars. This one is quite simple to be readable by humans. Yes, we are humans if you raise the question! =)

The header of our EBNF describes some terms and conventions, but here is a small subset of our grammar:

FromClause                        ::= "FROM" IdentificationVariableDeclaration {"," IdentificationVariableDeclaration}*
IdentificationVariableDeclaration ::= RangeVariableDeclaration [IndexBy] {JoinVariableDeclaration}*
RangeVariableDeclaration          ::= AbstractSchemaName ["AS"] AliasIdentificationVariable
AbstractSchemaName                ::= identifier
AliasIdentificationVariable       ::= identifier

It’s not mentioned in this subset some pieces just for clarity. Identifier is a terminal (no grammar rule to follow after that) and is a string (ie. “name”, “email”).

What does this subset do?

It processes this pieces of DQL:

FROM User u
FROM User AS u, u.Group g

How does it do that?

Each piece of DQL is converted to a series of tokens. Some tokens are defined in our Symbol Table , which is then validated and correctly typed into the right token type. For example... when it finds the “FROM”, it’ll return for us internally a token in an array format of:

array(
    'value' => 'FROM',
    'type' => Lexer::T_FROM,
    'position' => 0
)

Value is the actual string representation in DQL, type is the token type that was brought by symbol table and position is the position of this token in the DQL string.

Then token is validated in the DQL parser; if it is expected the T_FROM, just match and go to next token, if not raise a syntax error. Imagine someone types this: “FROM User u, u.Group u”. It is not valid DQL, because alias “u” is being used twice. That is the task of another check, which inspects the requested DQL defined symbol table and reports for semantical errors. We removed the lexical errors since we use them as identifiers, so there is no lexical error checks in DQL. Not that it may open a hole in our structure, syntax and semantical checks do all that we need.

How can I help?

We currently have a single test that checks for DQL recognition. We need to expand it to cover as much situations as possible. If you follow the EBNF grammar rules, you’ll see that for example, IN condition supports either a series of Literals (which can be strings, booleans, etc), an InputParameter or a subselect. We need some people with free time to cover all possible situations; I mean that we needs something like these queries:

SELECT u FROM CmsUser u WHERE u.id IN (1, 2)

SELECT u FROM CmsUser u WHERE u.id IN (?0)

SELECT u FROM CmsUser u WHERE u.name IN ('guilhermeblanco', 'jwage', 'romanb')

SELECT u FROM CmsUser u WHERE u.id IN (SELECT u2.id FROM CmsUser u2)

By doing (sometimes) stupid queries and complex queries, we cover all possibilities and then we can finally consider that we have a good coverage in our DQL support.

If you load the LanguageRecognitionTest , you’ll find that we have already builtin 2 methods to help you asserting DQL support: assertValidDql and assertInvalidDql. Just follow the EBNF, pick defined models under Models/CMS folder and start writing tests.

Running tests

It is not hard to execute new test suite. Once you have PHPUnit and XDebug installed, go to tests folder of trunk, create the directory _coverage (CHMOD 0777) and execute:

phpunit --coverage-html=./_coverage Doctrine_Tests_AllTests

Then you’ll have coverage too, which means it’ll be even better to see where it’s missing tests in suite.

Once you write your tests, create a ticket in our trac and then upload the patched file there. We’ll review your tests and commit them.

To generate a patch file, just type: svn diff > /path/to/path/file.diff I hope you enjoy new structure and contribute with lots of tests!

]]>
Tue, 04 Aug 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/07/27/doctrine-1-0-11-and-1-1-3-released.html http://www.doctrine-project.org/2009/07/27/doctrine-1-0-11-and-1-1-3-released.html <![CDATA[Doctrine 1.0.11 and 1.1.3 Released]]>

Doctrine 1.0.11 and 1.1.3 Released

Today I am happy to introduce two new maintenance releases for Doctrine, 1.0.11 and 1.1.3. As always these are regular maintenance releases and contain dozens of bug fixes. Below you will find links to view the changelogs for both releases.

It is recommended that you upgrade as soon as possible. You can download the new versions from the download page.

]]>
Mon, 27 Jul 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/07/04/major-site-enhancements.html http://www.doctrine-project.org/2009/07/04/major-site-enhancements.html <![CDATA[Major Site Enhancements]]>

Major Site Enhancements

You’ve probably noticed over the past few days I have rolled out some major new site enhancements. You can find more information below about all the changes made.

Register Now!

I have opened up a new registration portal on the Doctrine website. This will create a login both on the website and Trac and is also connected to your SVN account if you choose to request access.

Login Now!

Once you have registered you can login to the website and Trac. This will make some extra functionality available for you to manage your user information.

New Extensions Repository

A place where you can browse, search and find out what extensions are available for Doctrine. It contains documentation, ability to run the unit tests and download the code.

Check it out here.

User Documentation Area

For a long time I have wanted to have an area of the website where users could manage as much user contributed documentation as they want. I have started the new site with a tutorial on how to write an extension.

New Homepage Look

I have slightly tweaked the homepage design to match the design of the new Doctrine book. This is our first book so if you want to support the Doctrine project or just want to learn about Doctrine then we suggest you purchase a copy! :)

Manage your User Account

Central location where you can manage all the information you control as a Doctrine authenticated user. You can see what extensions you’ve written, control your user contributed documentation, request SVN access and update your account information. Check it out here.

These changes are primarily based around the new extensions repository which is available for Doctrine 1.2. You can read about what else is new in Doctrine 1.2 here.

]]>
Sat, 04 Jul 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/06/30/doctrine-orm-for-php-available-in-print.html http://www.doctrine-project.org/2009/06/30/doctrine-orm-for-php-available-in-print.html <![CDATA[Doctrine ORM for PHP available in print]]>

Doctrine ORM for PHP available in print

Last night the Doctrine ORM for PHP book became available on the Amazon website. This is our first official piece of published documentation and we are very excited and proud to see this.

If you are an existing or new Doctrine user, it is much appreciated if you purchase a copy. Since Doctrine is an open source project we don’t make any money directly from it. Doctrine is all possible because of the contributors and the companies that fund it, like Sensio Labs. So it is a very nice gesture, even if you are already a Doctrine expert, to purchase a copy of the book to show your appreciation and support for the project.

]]>
Tue, 30 Jun 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/06/28/introducing-the-google-i18n-extension.html http://www.doctrine-project.org/2009/06/28/introducing-the-google-i18n-extension.html <![CDATA[Introducing the Google I18n Extension]]>

Introducing the Google I18n Extension

]]>
Sun, 28 Jun 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/06/26/what-s-new-in-doctrine-1-2.html http://www.doctrine-project.org/2009/06/26/what-s-new-in-doctrine-1-2.html <![CDATA[What's new in Doctrine 1.2]]>

What’s new in Doctrine 1.2

This week I have been working on the next major version of Doctrine, 1.2. This version will possibly be the last 1.x version before we really begin to push 2.0 hard.

The 1.2 release should be a decent release for you all and I think it has some interesting features that should really spark some growth in the community around Doctrine. Here are some highlights.

Highlights

  • Major cleanup, removing deprecated methods, removed accessor string support for performance fix
  • Option to disable cascading saves by default for performance improvement
  • Changes to migrations to better handle migrating multiple databases
  • More configuration options
  • Configure a child Doctrine_Query class to use
  • Configure a child Doctrine_Collection class to use
  • Refactored hydration implementation to be completely driver based
  • Write your own hydration drivers to process query statements
  • Refactored Doctrine connections to be completely driver based
  • Write your own connection drivers for Doctrine
  • Other small changes and improvements across the code base

Doctrine Extensions

All the above changes lend themselves well to creating extensions and behaviors for Doctrine. This has led to the creation of the Doctrine extensions repository.

You can now write standalone code bundled as a Doctrine extension that can be dropped in to an extensions folder and loaded by Doctrine. So now when you all write custom behaviors and custom extensions you can make them available for other people to use and drop in to projects.

I have started the repository by committing the Sortable behavior which was contributed by a Doctrine user on our trac. So whoever you are, if you would like to maintain this extension please contact me.

Follow 1.2 Development

If you want to know more about Doctrine 1.2 you can read the What’s new in Doctrine 1.2 document which will be kept up to date as we develop and change things in 1.2!

CAUTION Some of the implemented features in 1.2 are still being discussed and debated so they may change or be completely removed if decided so. If you have any input or suggestions on the provided features, let us know ASAP.
]]>
Fri, 26 Jun 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/06/24/thank-you-servergrove.html http://www.doctrine-project.org/2009/06/24/thank-you-servergrove.html <![CDATA[Thank you ServerGrove]]>

Thank you ServerGrove

As you all may know, we recently moved the Doctrine infrastructure to a brand new home. This is all thanks to ServerGrove. I contacted them a few months ago about potentially sponsoring us and they did not hesitate one bit. They were more than willing to setup a dedicated community server for us, free of charge. Within 48 hours of my e-mail I had a dedicated server ready to go. I had the server for about a month before I was able to make the move. They simply moved faster then I expected and have gone above and beyond anything I could have imagined.

If you all need proper hosting support for your Symfony or Doctrine projects, I would highly recommend them.

]]>
Wed, 24 Jun 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/06/21/website-updates.html http://www.doctrine-project.org/2009/06/21/website-updates.html <![CDATA[Website Updates]]>

Website Updates

Today I have deployed some updates to the Doctrine website. Some of the updates all of you will enjoy, but another specific one might upset some of you.

I have decided to remove the Doctrine Forum forever and consolidate the user discussions in to the doctrine-user mailing list which is hosted on Google Groups. I chose to do this for a few reasons.

  • Consolidate discussions in to one area so the community is not split.
  • phpBB is horrible and is proving to be a lot of work for me to maintain
  • I don’t want to have to spend countless hours maintaining something that google groups can do for me, for free

I know this will upset some of you, but I hope you understand and are happy that the Doctrine developers will now be able to spend more time...**developing Doctrine**..instead of maintaining the forum.

Some other changes I have made/fixed.

  • Change Logs are now fixed from the move
  • The blog has been enhanced and tags fixed
  • API Documentation Enhanced to include browse code links so you can see the code for each class, function, etc.
  • A bunch of other small little things tweaked and fixed.

If you find anything wrong with the website or something you’d like to see different please let me know via the comments below or by e-mail at jonwage [at] gmail.com

]]>
Sun, 21 Jun 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/06/21/doctrine-future-roadmap.html http://www.doctrine-project.org/2009/06/21/doctrine-future-roadmap.html <![CDATA[Doctrine Future Roadmap]]>

Doctrine Future Roadmap

So, lately we’ve been discussing and getting a lot of questions about the future roadmap of Doctrine, specifically 2.0. If you are following PHP 5.3 you will have noticed that PHP 5.3 RC4 was released last week. This means that the stable release of 5.3 is very near.

Below you will find a schedule of the roadmap we have planned for the upcoming months/years.

| Date | Item | | ————– | ———————————————— | | 06/22/2009 | Branch Doctrine 1.2 | | 06/24/2009 | PHP 5.3.0 Stable Release (YES!!!) | | 09/2009 | Begin 1.2 release cycle. Alpha, Beta, RC, Stable | | 09/2009 | Final 6 months of 1.0 Support | | 09/2009 | Launch 2.0 Alpha 1 | | 11/2009 | Launch 1.2.0 with Long Term Support (18 months) | | 11/2009 | Symfony 1.3 + Doctrine 1.2 | | 11/2009 | End Doctrine 1.1 Support | | 03/2010 | End Doctrine 1.0 Support | | 03/2010 | Continue 2.0 release cycle | | ??/2010 | Release 2.0.0 with Long Term Support (18 months) | | 06/2011 | End Doctrine 1.2 Support |

We hope that the above timeline gives PHP 5.3 plenty of time to be adopted before we officially stop support for the Doctrine 1.x series. We think it will be plenty of time but depending how things play out, we can always add more time to the support life cycle of the 1.x series, but we hope to not have to. So, this Wednesday when PHP 5.3 is released, please switch to it if you can and help with the adoption.

]]>
Sun, 21 Jun 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/06/19/using-views-with-doctrine.html http://www.doctrine-project.org/2009/06/19/using-views-with-doctrine.html <![CDATA[Using Views with Doctrine]]>

Using Views with Doctrine

I’ve seen a few requests recently on how you can use a view with Doctrine. This is very easy and I’ve also learned a few neat tricks that you can do to accomplish abnormal things while writing this article.

Creating the View

First I will demonstrate how you can turn a normal Doctrine_Query instance in to a view. This is just as easy as creating an instance of Doctrine_View and setting a reference between the query and the view.

<?php
$q = Doctrine::getTable('BlogPost')
  ->createQuery('p')
  ->select('p.*, COUNT(c.id) as num_comments')
  ->leftJoin('p.Comments c')
  ->orderBy('p.id DESC')
  ->groupBy('p.id');

$view = new Doctrine_View($q, 'test_view');

To create the view in the database you can call the Doctrine_View::create() method.

<?php
$view->create();

**TIP** You can drop the view just the same by calling the
``Doctrine_View::drop()`` method.
<?php
    $view->drop();

Executing the View

Now when the Doctrine_Query instance above is executed, it will execute the SQL for the view instead of parsing the DQL, generating the SQL and executing it.

<?php
$blogPosts = $q->execute();

Executing the above would execute the following SQL query.

[sql]
SELECT * FROM test_view

Tweaking the View

Now here is where things get interesting. Say we wanted to take the SQL that the above Doctrine_Query generates, and modify it slightly with some custom SQL that otherwise could not make it through the DQL parser.

We can get the SQL from the query, modify it, then manually create the view in our database.

<?php
echo $q->getSql();

The above would output the following SQL.

[sql]
SELECT b.id AS b__id, b.title AS b__title, b.excerpt AS b__excerpt, b.body AS b__body, COUNT(c.id) AS c__0 FROM blog_post b LEFT JOIN comment c ON b.id = c.blog_post_id GROUP BY b.id ORDER BY b.id DESC

Now lets say we wanted to add something to the SQL that is proprietary to your DBMS, or is some complex SQL that won’t make it through the DQL parser. We can modify the above SQL then re-create the view with that SQL manually. Let’s make a simple change and add the USE INDEX keyword to force MySQL to use a certain index for the query.

NOTE The example I have chosen is a very simple one only to demonstrate the capabilities. This example may not be a real world scenario for you. The only purpose of me showing this is to open a door for you to solve potential problems for you in the future.
[sql]
SELECT b.id AS b__id, b.title AS b__title, b.excerpt AS b__excerpt, b.body AS b__body, COUNT(c.id) AS c__0 FROM blog_post b LEFT JOIN comment c USE INDEX (blog_post_id_idx) ON b.id = c.blog_post_id GROUP BY b.id ORDER BY b.id DESC;

Now lets take this query and manually create the view with it.

NOTE We must first drop the view as we already created it once in a previous step. This is just as easy as issuing the DROP VIEW command to MySQL. Afterward, re-create the view again with the modified SQL.
[sql]
DROP VIEW test_view;
CREATE VIEW test_view AS SELECT b.id AS b__id, b.title AS b__title, b.excerpt AS b__excerpt, b.body AS b__body, COUNT(c.id) AS c__0 FROM blog_post b LEFT JOIN comment c USE INDEX (blog_post_id_idx) ON b.id = c.blog_post_id GROUP BY b.id ORDER BY b.id DESC;

Now when we execute the code in the first part of this article it will execute the view which contains the customized SQL.

<?php
$blogPosts = $q->execute();

**CAUTION** If you customize the SQL, it must maintain the same
structure, aliases, etc. in order for Doctrine to be able to
hydrate the data in to the object graph.

That is it! Now you can easily use some custom SQL in your queries as views. The benefit of using a view is that it is easily reusable and it is much faster than executing a normal query in most cases.

]]>
Fri, 19 Jun 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/06/19/cross-database-joins.html http://www.doctrine-project.org/2009/06/19/cross-database-joins.html <![CDATA[Cross Database Joins]]>

Cross Database Joins

Cross Database Joins

In Doctrine, joining data across databases is not technically “supported” by a designed feature, but you can make it work by tricking Doctrine a little bit.

In this article I’ll show you how you can setup a database schema that specifies relationships across two databases and then issue a query which joins data from these two databases.

I used the Doctrine sandbox to prepare this test so if you want to try it, you can use it too.

Database Connections

First lets setup our two database connections we’ll use to query from. Modify the config.php file included with the sandbox and replace the default single connection with the following code.

<?php
Doctrine_Manager::connection('mysql://root@localhost/doctrine_test1', 'doctrine_test1');
Doctrine_Manager::connection('mysql://root@localhost/doctrine_test2', 'doctrine_test2');

Schema

Now lets define our YAML schema file that we’ll use to run our tests against. You can modify the config/doctrine/schema.yml file and include the following YAML.

[yml]
User:
  tableName: doctrine_test1.user
  connection: doctrine_test1
  columns:
    username: string(255)
    password: string(255)

Profile:
  tableName: doctrine_test2.profile
  connection: doctrine_test2
  columns:
    user_id: integer
    first_name: string(255)
    last_name: string(255)
  relations:
    User:
      foreignType: one
      onDelete: CASCADE

**NOTE** Notice how we specify the full table name, including the
name of the database. Currently, Doctrine does not generate the SQL
that includes the database name. It only includes the table name,
but we can trick Doctrine by simply specifying the
``database_name.table_name`` as the table name.

Test Data Fixtures

In the data/fixtures directory create a data.yml file and paste the following fixtures inside so we can have some data in each database to run our tests against.

[yml]
User:
  jwage:
    username: jwage
    password: changeme
    Profile:
      first_name: string(255)
      last_name: string(255)

Build the Database

Now lets build our database and import the data fixtures from above. This can be easily done by running the following from the Doctrine command line interface.

$ php doctrine build-all-reload

Run the Test

Now we have our models created, we have our database created and we have our test fixtures loaded in to the database. Now it is time to run some sample code and see what we get!

First lets write our Doctrine_Query and look at the generated SQL. Paste the following code in to index.php and lets execute it!

<?php
$q = Doctrine::getTable('User')
  ->createQuery('u')
  ->leftJoin('u.Profile p');

echo $q->getSql();

The above code would output the following SQL query.

[sql]
SELECT d.id AS d__id, d.username AS d__username, d.password AS d__password, d2.id AS d2__id, d2.user_id AS d2__user_id, d2.first_name AS d2__first_name, d2.last_name AS d2__last_name FROM doctrine_test1.user d LEFT JOIN doctrine_test2.profile d2 ON d.id = d2.user_id

**NOTE** Notice how in the above SQL that is generated it include
the database name and the table name. So now the query is able to
join across databases if your RDBMS supports it.

Now lets execute the above query and look at the results.

<?php
$q = Doctrine::getTable('User')
  ->createQuery('u')
  ->leftJoin('u.Profile p');

$users = $q->fetchArray();

print_r($users);

The above would output just exactly what you’d expect.

Array
(
    [0] => Array
        (
            [id] => 1
            [username] => jwage
            [password] => changeme
            [Profile] => Array
                (
                    [id] => 1
                    [user_id] => 1
                    [first_name] => string(255)
                    [last_name] => string(255)
                )

        )

)

The data from the User model came from one database, and the data from the Profile model came from the other database.

NOTE This will only work if your database supports foreign keys and joins across databases. I know MySQL does support this but I am unsure about others. This same method can be used to query for data across PostgreSQL schemas too.

That is it! Joining data from across different databases is no problem in Doctrine.

CAUTION This is not a designed feature of Doctrine and you may experience edge cases that may not work as you’d expect. This is just useful if you need to join data across databases and if you experience edge cases you can work around them in your project.
]]>
Fri, 19 Jun 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/06/17/special-price-offer-symfony-1-2-doctrine-training-workshop.html http://www.doctrine-project.org/2009/06/17/special-price-offer-symfony-1-2-doctrine-training-workshop.html <![CDATA[Special Price Offer: Symfony 1.2 + Doctrine Training Workshop]]>

Special Price Offer: Symfony 1.2 + Doctrine Training Workshop

As you all may know, I work for Sensio Labs , the creators of the Symfony framework. Sensio offers trainings in many topics, but primarily Symfony and Doctrine. I will be teaching a training session June 29th to July 1st in the San Francisco bay area that covers Symfony 1.2 and Doctrine 1.0. We are having a little issue completely filling the class and I need a few more trainees in order to fill the class to maintain the date, otherwise we’ll have to cancel.

I am able to make a special offer to any interested parties on the price of the training. All things are negotiable. So if you would like to attend the 3 day workshop taught by myself and learn the best practices when using Symfony and Doctrine, contact me right away! Remember, the price is completely negotiable so if you’re a student or a member of a development team and would like to attend please contact me so we can negotiate a price that works for you.

You can contact me at jonathan.wage@sensio.com to discuss details.

]]>
Wed, 17 Jun 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/06/16/doctrine-changing-homes.html http://www.doctrine-project.org/2009/06/16/doctrine-changing-homes.html <![CDATA[Doctrine changing homes]]>

Doctrine changing homes

You all may have noticed the stability of the website going up and down recently. Up until now we have been lucky to have our good friend Ian Christian(pookey in IRC) host all the Doctrine infrastructure for over 3 whole years! With Doctrine continuing to grow and move forward, it is time to move on to greener pastures to a dedicated home.

Tonight we will try to begin the migration to our new home. Hopefully this transition will be fairly seamless but we expect at least a little downtime. We are moving the website, Trac and SVN all at once to avoid the migration lasting over a long period of time. Thanks for your patience while we work through these issues.

]]>
Tue, 16 Jun 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/06/15/sensio-labs-training-sessions.html http://www.doctrine-project.org/2009/06/15/sensio-labs-training-sessions.html <![CDATA[Sensio Labs Training Sessions]]>

Sensio Labs Training Sessions

If you’re a PHP developer and would like to get familiar with the concepts behind MVC Frameworks and ORMs then you should attend one of the Sensio Labs hosted training sessions taught by one of our expert consultants.

The course covers many topics such as:

  • Refactoring a flat file PHP application in to a MVC framework
  • Templating
  • Working environment
  • Routing and HTTP protocol
  • Object Relational Mapper
  • Using the session
  • Unit and Functional Testing
  • Caching your data

The training utilizes the Symfony MVC framework and the Doctrine Object Relational Mapper as the tools of choice for the workshop.

If you are interested in attending one of these sessions please contact me at jonathan.wage@sensio.com so we can discuss details.

]]>
Mon, 15 Jun 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/06/15/doctrine-1-0-10-and-1-1-2-released.html http://www.doctrine-project.org/2009/06/15/doctrine-1-0-10-and-1-1-2-released.html <![CDATA[Doctrine 1.0.10 and 1.1.2 Released]]>

Doctrine 1.0.10 and 1.1.2 Released

Today I am happy to release two new maintenance releases for Doctrine. As usual we have a new version for the 1.0 branch and a new version for the 1.1 branch. The new versions can be gotten on the Download page.

You can review the changelogs for 1.0.10 and 1.1.2 to see what all issues have been addressed in these releases.

On a side note, development on the Doctrine 1.2 version will begin very soon so if you have any ideas or features you’d like to see in this version please bring them to our attention and we may be able to address them in this version. We plan for the 1.2 version to concentrate on bug fixes, performance fixes and small features to make the use of the 1.x version of Doctrine more enjoyable without any major BC breaks.

]]>
Mon, 15 Jun 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/06/13/doctrine-visiting-conferences-around-the-world.html http://www.doctrine-project.org/2009/06/13/doctrine-visiting-conferences-around-the-world.html <![CDATA[Doctrine visiting conferences around the world]]>

Doctrine visiting conferences around the world

This last month I have been present at a few events to speak about Doctrine. I visited Verona, Italy for the phpDay conference and this last week I was present at the first Symfony conference in Paris, France. I also have given a few talks at some smaller local events such as the Nashville Enterprise LAMP group. Below are the links to the presentations on slideshare.

What’s new in Doctrine (symfony live)

What’s new in Doctrine

View more Microsoft Word documents from jwage.

What is Doctrine? (Nashville LAMP Group)

What Is Doctrine?

View more Microsoft Word documents from jwage.

What’s new in Doctrine (phpDay 2009)

What’s New In Doctrine

View more Microsoft Word documents from jwage.

In addition to the Doctrine talks I have been talking a lot recently about a new CMS built on top of Symfony and Doctrine called Sympal. Below you can view those presentations as well if interested.

Sympal - The flexible Symfony CMS (symfony live)

Sympal - The flexible Symfony CMS

View more Microsoft Word documents from jwage.

Sympal - The flexible Symfony CMS (phpDay 2009)

Sympal - The Flexible Symfony Cms

View more Microsoft Word documents from jwage.

]]> Sat, 13 Jun 2009 00:00:00 +0000 http://www.doctrine-project.org/2009/06/05/doctrine-statistics.html http://www.doctrine-project.org/2009/06/05/doctrine-statistics.html <![CDATA[Doctrine Statistics]]>

Doctrine Statistics

On October 18th of 2007 I implemented Google Analytics which allowed me to track the statistics of the website. On that first day of statistics gathered we had 93 visitors and yesterday we had a little over 1500! Needless to say that is pretty exciting!

Here is a graph from google analytics that illustrates the growth.

Here are some more statistics gathered:

Google Analytics

| Statistics | | | —– | —— | | Visits | 607,035 | | Absolute Unique Visitors | 232,366 | | Pageviews | 2,331,993 | | Average Pageviews | 3.84 | | Time on Site | 00:05:02 | | Bounce Rate | 42.31% | | New Visits | 38.19% |

Downloads

| Version | # | | ———- | —| | 0.9 | 126 | | 0.10 | 7521 | | 0.11 | 6691 | | 1.0 | 20300 | | 1.1 | 9539 |

NOTE These statistics don’t count downloads through other sources such as symfony, Doctrine SVN, etc. They only track the downloads through the Doctrine website on the `Download <http://www.doctrine-project.org/download>`_ page.

Hopefully I can make this same post a year from now about the same thing and Doctrine will have grown with many new versions.

]]>
Fri, 05 Jun 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/05/29/doctrine-lazy-loading.html http://www.doctrine-project.org/2009/05/29/doctrine-lazy-loading.html <![CDATA[Doctrine Lazy Loading]]>

Doctrine Lazy Loading

Did you know?

Did you know that in Doctrine if you don’t specifically select a property or join a relationship in your DQL query, you can lazily load that data? Here is a simple example to demonstrate.

<?php
$q = Doctrine::getTable('User')
  ->createQuery('u')
  ->select('u.id, u.username')
  ->where('u.username = ?', 'jwage');

$user = $q->fetchOne();

Notice how I only selected the id and username, but we have an additional column named email_address. If I were to access that property it would lazily load the data.

<?php
echo $user['email_address']

**NOTE** The above code would result in an additional query to the
database that would lazy load all unloaded properties of an object
in proxy state. A record is in proxy state when it has one or more
properties that have not been loaded from the database.

Be aware

This can be both a curse and a blessing because if you lazily load many properties and relationships this means you will have a high query count per page. In Doctrine 1.x lazy loading is on by default so it is often overly used. The problem is people aren’t even aware that it is happening.

More Examples

Imagine you had a User and Profile model where User has one Profile and Profile has one User, a simple one-to-one relationship. If I were to write a DQL query where I retrieve an individual user record like the following.

<?php
$q = Doctrine::getTable('User')
  ->createQuery('u')
  ->where('u.username = ?', 'jwage');

$user = $q->fetchOne();

But then I wanted to retrieve the Profile for that User I could do so by simply accessing the Profile property on User.

<?php
$profile = $user->Profile;

The above code would result in an additional query to the database that loads the Profile record for the User in question. Now if I were to be rendering a list of twenty User objects and I lazily load the profile of each user that means I would have 21 queries total! That is too many! In that case it would be smart to leftJoin() the Profile object like the following.

<?php
$q = Doctrine::getTable('User')
  ->createQuery('u')
  ->leftJoin('u.Profile p');

$users = $q->execute();

Now when I access the Profile relationship of an individual object the data would already be present and no lazy loading would be required.

Why?

I made this blog post because I noticed this feature being abused and overly used just because it makes things easier. The goal is to make you aware of what is happening so that you can effectively use lazy loading and not end up having applications with very high query counts per page.

I’ve seen this many times and the blame is often put on Doctrine but really it is the tool not being used properly. So, be aware of when you are lazy loading properties and the total number of queries you execute per page. Make sure you always join required relationships and only select the properties you need to access. It doesn’t make sense to load data if you’re not going to be using it.

How?

If you need help with keeping track of how many queries you have per page, frameworks like Symfony and Zend Framework give you debug tools to show you how many queries you have per page. Or of course you can always use the Profiling tool built in to Doctrine to log the queries in your application and keep track of it that way.

]]>
Fri, 29 May 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/05/28/doctrine-database-abstraction-layer.html http://www.doctrine-project.org/2009/05/28/doctrine-database-abstraction-layer.html <![CDATA[Doctrine Database Abstraction Layer]]>

Doctrine Database Abstraction Layer

One of the greatest advantages to using Doctrine is what is under the hood that powers it. That is the database abstraction layer. This powerful layer is based off of a lot of different code from various popular PHP projects such as PEAR MDB2 and Zend_Db. It provides you a nice intuitive interface for retrieving information about your database schema as well as issuing DDL statements to change it.

Public Method Index

The database abstraction layer features the following methods in 1.x and some new methods added in 2.0.

1.x Methods

  • listDatabases()
  • listFunctions()
  • listTriggers()
  • listSequences()
  • listTableConstraints()
  • listTableColumns()
  • listTableIndexes()
  • listTables()
  • listUsers()
  • listViews()
  • dropDatabase()
  • dropTable()
  • dropIndex()
  • dropConstraint()
  • dropForeignKey()
  • dropSequence()
  • createDatabase()
  • createTable()
  • createSequence()
  • createConstraint()
  • createIndex()
  • createForeignKey()
  • alterTable()

New Methods in 2.0

  • renameTable()
  • addTableColumn()
  • removeTableColumn()
  • changeTableColumn()
  • renameTableColumn()
  • dropView()
  • createView()

Some 2.0 Examples

Here are some code examples using the Doctrine 2.0 Database Abstraction Layer. We’ll show you how you can execute these examples yourself by checking out Doctrine 2.0 from SVN and setting up a PHP script to test with.

TIP The database abstraction layer can be used standalone so if you just want a nice standard layer for communicating with your database then Doctrine works for you too.

Checkout Doctrine

$ svn co http://svn.doctrine-project.org/trunk doctrine2
$ cd doctrine2

Create Test Script

Create a new PHP script anywhere on your server and name it test.php. Now lets initialize Doctrine so we can work with it. First we need to set our ClassLoader.

<?php
// test.php

require 'lib/Doctrine/Common/ClassLoader.php';

$classLoader = new \Doctrine\Common\ClassLoader();
$classLoader->setBasePath('Doctrine', __DIR__ . '/lib');

Create Connection

Now we need to create our Connection instance.

<?php
// test.php

// ...

$connectionOptions = array(
    'driver' => 'pdo_mysql',
    'dbname' => 'mysql',
    'user' => 'root',
    'password' => ''
);
$driver = new \Doctrine\DBAL\Driver\PDOMySql\Driver;
$conn = new \Doctrine\DBAL\Connection($connectionOptions, $driver);

**NOTE** Notice how we are temporarily connecting to the special
database for MySQL named ``mysql``. We'll use this database to
connect to so we can create our test database.

Now we can simply retrieve the SchemaManager instance from the Connection driver and begin to execute some of the methods we listed above.

<?php
// test.php

// ...

$sm = $conn->getSchemaManager();

The first thing we could do is create the database by calling the createDatabase() method on the $sm instance.

<?php
// test.php

// ...

$sm->createDatabase('doctrine2test');

Now that we have the database created, change your $connectionOptions key dbname to specify doctrine2test so that we connect to the new database that we just created.

<?php
// test.php

// ...

$connectionOptions = array(
    'driver' => 'pdo_mysql',
    'dbname' => 'doctrine2test',
    'user' => 'root',
    'password' => ''
);

// ...

Now we can begin adding things to the new database. For example we could issue a command to create a new table.

<?php
// test.php

// ...

$columns = array(
    'id' => array(
        'type' => \Doctrine\DBAL\Type::getType('integer'),
        'autoincrement' => true,
        'primary' => true,
        'notnull' => true
    ),
    'test' => array(
        'type' =>  \Doctrine\DBAL\Type::getType('string'),
        'length' => 255
    )
);

$options = array();

$sm->createTable('new_table', $columns, $options);

Then after creating the table I can later add a new column to it.

<?php
// test.php

// ...

$column = array(
    'type' =>  \Doctrine\DBAL\Type::getType('string'),
    'length' => 255
);

$sm->addTableColumn('new_table', 'new_column', $column);

Or I could even drop the table completely.

<?php
// test.php

// ...

$sm->dropTable('new_table');

**NOTE** Not all of the above listed methods are supported by every
single DBMS. If your DBMS does not support the functionality then
Doctrine will throw exceptions accordingly.

All the above example are very simple schema changes but Doctrine is capable of manipulating very complex schemas from a standardized programmatic interface. The Doctrine Migrations extension makes use of this layer heavily to do all the operations for changing your database schemas.

]]>
Thu, 28 May 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/05/27/want-to-contribute-to-doctrine.html http://www.doctrine-project.org/2009/05/27/want-to-contribute-to-doctrine.html <![CDATA[Want to contribute to Doctrine?]]>

Want to contribute to Doctrine?

Looking for Developers

We’ve been on the hunt for more Doctrine contributors. As the number of users of Doctrine grew we expected the number of commiters to rise with it but this has not been the case. We do get a lot of small patches here and there, but we are hoping for some of them to grow in to full-time core developers that are involved with all the decisions made about Doctrine.

Call to the community

You can see Roman made a call to the Doctrine developers mailing list here about the issue. We are taking all the feedback in to consideration and we have started by creating a contribute page that is linked from the primary menu of the website. We hope that this will help with new users finding information faster about how they can get started contributing.

Other Ideas

If you have any additional ideas about how we can promote contributing to Doctrine you can discuss them in the comments or on the mailing list thread.

]]>
Wed, 27 May 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/05/22/glimpse-of-doctrine-2-0.html http://www.doctrine-project.org/2009/05/22/glimpse-of-doctrine-2-0.html <![CDATA[Glimpse of Doctrine 2.0]]>

Glimpse of Doctrine 2.0

As you all probably already know, we have been working on Doctrine 2.0 pretty much since before we released Doctrine 1.0. This effort has been primarily led by Roman and he has done an excellent job with things so first a big thanks goes to him.

A few quick facts

  • Doctrine 2.0 will require PHP 5.3
  • Doctrine 2.0 is FAST
  • We will extend the support life of 1.x

We have decided to move forward with Doctrine 2.0 requiring PHP 5.3. This release is a significant one, both for PHP and Doctrine, so we decided to continue support for the 1.x series of Doctrine to give the adoption of PHP 5.3 and Doctrine 2.0 more time.

Hydration Performance

In Doctrine 2.0 the performance when hydrating data is greatly improved. The difference in speed is a combination of code changes and the performance increase from using PHP 5.3.

| Version | Seconds | # Records | | ———- | ———— | ————- | | 1.1 | 4.3435637950897 | 5000 | | 2.0 | 1.4314442552312 | 5000 | | 2.0 | 3.4690098762512 | 10000 |

A few code snippets

Schema Metadata and Models

In Doctrine 1.1 a Doctrine_Record might look something like the following.

<?php
class User extends Doctrine_Record
{
    public function setTableDefinition()
    {
        $this->hasColumn('id', 'integer', null, array(
          'primary' => true,
          'auto_increment' => true
        ));
        $this->hasColumn('username', 'string', 255);
    }
}

**NOTE** Notice how you have to extend the base class and
everything is a public instance. As you probably know this has lots
of negative effects as it imposes properties and methods on your
models.

In Doctrine 2.0 this limitation was removed and you no longer need to extend a base class.

<?php
/**
 * @DoctrineEntity
 * @DoctrineTable(name="user")
 */
class User
{
    /**
     * @DoctrineId
     * @DoctrineColumn(type="integer")
     * @DoctrineGeneratedValue(strategy="auto")
     */
    public $id;
    /**
     * @DoctrineColumn(type="varchar", length=255)
     */
    public $username;
}

Custom Data Types

In Doctrine 2.0 you can write your own custom data types. Here is an example of what the custom datatype class might look like.

Type Declaration

<?php
namespace My\Project\Types;

use Doctrine\DBAL\Types\Type;
use Doctrine\DBAL\Platforms\AbstractPlatform;

/**
 * My custom datatype.
 */
class MyType extends Type
{
    public function getSqlDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
    {
        // return the SQL used to create your column type. To create a portable column type, use the $platform.
    }

    public function convertToPHPValue($value)
    {
        // This is executed when the value is read from the database. Make your conversions here.
    }

    public function convertToDatabaseValue($value, AbstractPlatform $platform)
    {
        // This is executed when the value is written to the database. Make your conversions here, optionally using the $platform.
    }
}

Adding Custom Type

You can easily register your custom type with Doctrine like this.

<?php
// in bootstrapping code

...

use Doctrine\DBAL\Types\Type;

...

// Register my type
Type::addCustomType('mytype', 'My\Project\Types\MyType');

Using Custom Type

Now in your model definition you can do something like the following.

<?php
namespace My\Project\Model;

/**
 * @DoctrineEntity
 * ...
 */
class MyEntity
{
    /**
     * @DoctrineColumn(type="mytype")
     */
    private $data;

    // ... other properties and code
}

This is only a small glimpse of what is possible in Doctrine 2.0. You will start to see more posts on the blog related to Doctrine 2.0 in the next several months so stay tuned.

]]>
Fri, 22 May 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/05/11/doctrine-1-0-9-and-1-1-1-released.html http://www.doctrine-project.org/2009/05/11/doctrine-1-0-9-and-1-1-1-released.html <![CDATA[Doctrine 1.0.9 and 1.1.1 Released]]>

Doctrine 1.0.9 and 1.1.1 Released

Today I am very happy to make available two new releases of Doctrine for the 1.0 and 1.1 code bases. These are both significant bug fix releases and it is recommended that you upgrade right away.

You can find more information about these releases as usual on the download page.

]]>
Mon, 11 May 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/03/16/doctrine-1-1-released.html http://www.doctrine-project.org/2009/03/16/doctrine-1-1-released.html <![CDATA[Doctrine 1.1 Released]]>

Doctrine 1.1 Released

Today I am very pleased to bring news to you that Doctrine 1.1.0 stable is available. This is a significant release for the 1.x code base. It contains dozens of new features and bug fixes. The 1.1 test suite now has 0 fails in the test suite compared to 1.0 having 12! We recommend you upgrade your projects.

NOTE Some have asked whether 1.1 has all the same bug fixes that are in 1.0. The answer is yes. We are committed to maintaining both branches and will continue committing fixes to all branches when it applies.

Highlights

  • New hydration methods
  • New migration diff tool
  • Better custom accessor/mutator support and integration with fromArray() and toArray()
  • Improvements to getModified(), toArray(), fromArray(), synchronizeWithArray()
  • Improvements to core behaviors Searchable, SoftDelete, Versionable
  • Dozens of small improvements and additions across the api
  • Plenty of other bug fixes

You can read a detailed list of all the changes made in 1.1 here in the upgrade file.

Download

As always you can get Doctrine on the download page or via pear.

$ pear install pear.phpdoctrine.org/Doctrine-1.1.0

You can also check it out via svn.

$ svn co http://svn.doctrine-project.org/tags/1.1.0/lib doctrine

If you find any problems with this release please report it on our trac or if you have any questions you can send it to one of our mailing lists.

]]>
Mon, 16 Mar 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/03/12/get-trained-by-doctrine-experts.html http://www.doctrine-project.org/2009/03/12/get-trained-by-doctrine-experts.html <![CDATA[Want to get trained by Doctrine experts?]]>

Want to get trained by Doctrine experts?

What is it?

Whether you are an individual or with a team of developers, you can get trained to use Doctrine by the professionals who built it and use it for everyday client projects! The sessions are available for standalone Doctrine or combined with the symfony MVC Framework. The training is a three day event where we cover some of the most important features of Doctrine and symfony.

When is it?

Below are some dates of up-coming training sessions for both standalone Doctrine as well as symfony 1.2 + Doctrine. We have several sessions in the US as well as Europe.

US Sessions

  • symfony 1.2 + Doctrine from Mar 23 to Mar 25, 2009 in Atlanta, Georgia
  • symfony 1.2 + Doctrine from Apr 22 to Apr 24, 2009 in San Francisco, California
  • Doctrine Standalone from Apr 26 to Apr 28, 2009 in San Francisco, California
  • symfony 1.2 + Doctrine in Nashville, TN (DATES UNDETERMINED)

Europe Sessions

  • symfony 1.2 + Doctrine from Mar 18 to Mar 20, 2009 in Marseille, France

  • symfony 1.2 + Doctrine from Apr 22 to Apr 24, 2009 in Paris, France

  • symfony 1.2 + Doctrine from Apr 27 to Apr 30, 2009 in Paris, France

  • symfony 1.2 Jobeet + Doctrine from Apr 28 to Apr 30, 2009 in Paris, France

  • symfony 1.2 + Doctrine from May 05 to May 07, 2009 in Toulouse, France

  • symfony 1.2 + Doctrine from May 27 to May 29, 2009 in Paris, France

  • symfony 1.2 + Doctrine from Jun 24 to Jun 26, 2009 in Paris, France

    NOTE Please note that all of the above european session dates are presented in French.

If you are interested in a training session involving Doctrine please contact me ASAP. If none of the above dates or locations work for you please contact me and we’ll let you know as soon as dates open for a session that works for you. You can reach me via e-mail at jonwage@gmail.com.


You can always see the live up-to-date SensioLabs training schedule here or on the homepage of the Doctrine website.

]]>
Thu, 12 Mar 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/03/03/doctrine-1-1-documentation.html http://www.doctrine-project.org/2009/03/03/doctrine-1-1-documentation.html <![CDATA[Doctrine 1.1 Documentation]]>

Doctrine 1.1 Documentation

Today I have begun updating the documentation to reflect the changes made in 1.1 and The Guide to Doctrine for PHP is now available. We still have some more changes to make but most things have been updated and added.

Below is a list of some of the things that still need some updating.

  • Migrations
  • SoftDelete
  • Searchable

Please lend a hand to us by reviewing the documentation and helping us identify things that are lacking or 100% missing. You can create new tickets in trac under the “Documentation/Website” milestone and we’ll get them fixed asap.

]]>
Tue, 03 Mar 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/03/02/doctrine-1-0-8-and-1-1-0-rc2-released.html http://www.doctrine-project.org/2009/03/02/doctrine-1-0-8-and-1-1-0-rc2-released.html <![CDATA[Doctrine 1.0.8 and 1.1.0-RC2 Released]]>

Doctrine 1.0.8 and 1.1.0-RC2 Released

Today I am happy to tell you that we have two new versions of Doctrine available for you to use. The first is the monthly maintenance release for Doctrine 1.0 and the second is another release candidate for the newest major version of Doctrine, 1.1. As always you can grab them from the downloads page.

1.0.8 Highlights

  • Backported a few fixes from 1.1
  • Several fixes and optimizations to Doctrine_Query::count()
  • Dozens and dozens of other small fixes

You can read the full change log for the 1.0.8 release here.

1.1.0-RC2 Highlights

  • Fixed issue with migration diff not paying attention to table options
  • Made the SoftDelete behavior backwards compatible with 1.0
  • Several fixes and optimizations to Doctrine_Query::count()
  • Fixed duplicated params when using LIMIT/OFFSET under MySQL
  • Fixed issue with new utf8 search analyzer
  • Fixed issue with prefixes causing invalid results in the migration diff tool
  • Fixed issues that arrise when re-using query objects with DQL callbacks enabled.

You can read the full change log for the 1.1.0-RC2 release here.


I realize we are a little late on the 1.1.0 release but we had some regressions reported that were a bit tricky and time consuming to fix. All is well now and we were able to make hopefully the last release candidate for the 1.1 version of Doctrine.

]]>
Mon, 02 Mar 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/02/04/using-behaviors-to-share-relationship-properties.html http://www.doctrine-project.org/2009/02/04/using-behaviors-to-share-relationship-properties.html <![CDATA[Using Behaviors to Share Relationship Properties]]>

Using Behaviors to Share Relationship Properties

Define The Schema

In this article we will demonstrate some more ways to add functionality to Doctrine by using the behavior system. We will call this behavior SharedProperties and it allows you to share properties between your models and one-to-one relationships. Here is an example schema that will make use of the behavior we will write.

[yml]
Entity:
  actAs:
    Sluggable:
      fields: [name]
    Timestampable:
  columns:
    name: string(255)
    is_active:
      type: boolean
      default: false

BlogPost:
  actAs:
    SharedProperties:
      relations: [Entity]
  columns:
    title: string(255)
    body: clob

User:
  actAs:
    SharedProperties:
      relations: [Entity]
  columns:
    username: string(255)
    password: string(255)

Administrator:
  actAs:
    SharedProperties:
      relations: [User]
  columns:
    responsibilities: string(255)

The schema should be somewhat self-explanatory. Each model that acts as SharedProperties you must specify an array of model names or existing relationship aliases. Our behavior will automatically add foreign keys for the list of models and instantiate a one-to-one relationship between the models automatically.

Write the Template

Lets write the first part of our template that simply adds a column for each of the listed relations:

<?php
class SharedProperties extends Doctrine_Template
{
    protected $_options = array();

    public function __construct($options)
    {
        $this->_options = $options;
    }

    public function setTableDefinition()
    {
        foreach ($this->_options['relations'] as $relation) {
            $columnName = Doctrine_Inflector::tableize($relation) . '_id';
            if (!$this->_table->hasColumn($columnName)) {
                $this->hasColumn($columnName, 'integer');
            }
        }
    }
}

**NOTE** You will notice we add columns for each of the
``relations`` specified if the column does not already exist. We
will use these columns to automatically create the
relationships/foreign keys between the models if they don't already
exist in the next step.

Enhance the Template

Now lets enhance our template and add a setUp() method to instantiate our relationships between the list of relations and the columns we added in the previous step:

<?php
class SharedProperties extends Doctrine_Template
{
    // ...

    public function setUp()
    {
        foreach ($this->_options['relations'] as $model) {
            $table = $this->_table;
            $local = Doctrine_Inflector::tableize($model) . '_id';
            $foreign = Doctrine::getTable($model)->getIdentifier();
            $this->_makeRelation($table, $model, $local, $foreign, true);
        }

        foreach ($this->_options['relations'] as $model) {
            $table = Doctrine::getTable($model);
            $local = $table->getIdentifier();
            $foreign = Doctrine_Inflector::tableize($model) . '_id';
            $this->_makeRelation($table, $this->_table->getOption('name'), $table->getIdentifier(), $foreign);
        }
    }

    protected function _makeRelation(Doctrine_Table $table, $model, $local, $foreign, $cascade = false)
    {
        if (!$table->hasRelation($model)) {
            $options = array('local'   => $local, 'foreign' => $foreign);
            if ($cascade) {
                $options['onDelete'] = 'CASCADE';
            }
            $table->bind(array($model, $options), Doctrine_Relation::ONE);
        }
    }
}

Generated SQL

This code we’ve added now makes a one-to-one relationship between the models that act as SharedProperties and the list of models specified. So for example, Entity has one BlogPost and BlogPost has one Entity. The above models at this point would generate the following SQL:

[sql]
CREATE TABLE administrator (id BIGINT AUTO_INCREMENT, responsibilities VARCHAR(255), user_id BIGINT, INDEX user_id_idx (user_id), PRIMARY KEY(id)) ENGINE = INNODB;

CREATE TABLE blog_post (id BIGINT AUTO_INCREMENT, title VARCHAR(255), body LONGTEXT, entity_id BIGINT, INDEX entity_id_idx (entity_id), PRIMARY KEY(id)) ENGINE = INNODB;

CREATE TABLE entity (id BIGINT AUTO_INCREMENT, name VARCHAR(255), is_active TINYINT(1) DEFAULT '0', slug VARCHAR(255), created_at DATETIME, updated_at DATETIME, UNIQUE INDEX sluggable_idx (slug), PRIMARY KEY(id)) ENGINE = INNODB;

CREATE TABLE user (id BIGINT AUTO_INCREMENT, username VARCHAR(255), password VARCHAR(255), entity_id BIGINT, INDEX entity_id_idx (entity_id), PRIMARY KEY(id)) ENGINE = INNODB;

ALTER TABLE administrator ADD FOREIGN KEY (user_id) REFERENCES user(id) ON DELETE CASCADE;

ALTER TABLE blog_post ADD FOREIGN KEY (entity_id) REFERENCES entity(id) ON DELETE CASCADE;

ALTER TABLE user ADD FOREIGN KEY (entity_id) REFERENCES entity(id) ON DELETE CASCADE;

Sharing Properties/Methods

Now to get to the fun, the main purpose of doing all this is to share the properties of these relationships. We can accomplish this by using the Doctrine_Record_Filter feature and some magic PHP __call() functionality. First lets modify our template to attach a new record filter.

TIP Records filters in Doctrine allow you to handle all unknown properties access on a Doctrine object. This allows us to forward the calls on to the relationships so you can access properties from them.
<?php
class SharedProperties extends Doctrine_Template
{
    // ...

    public function setTableDefinition()
    {
        // ...

        $this->_table->unshiftFilter(new SharedPropertiesFilter($this->_options));
    }

    // ...
}

Now that we have attached our filter we need to write that class:

<?php
class SharedPropertiesFilter extends Doctrine_Record_Filter
{
    protected $_options = array();

    public function __construct($options)
    {
        $this->_options = $options;
    }

    public function init()
    {
        foreach ($this->_options['relations'] as $model) {
            $this->_table->getRelation($model);
        }
    }

    public function filterSet(Doctrine_Record $record, $name, $value)
    {
        foreach ($this->_options['relations'] as $model) {
            try {
                $record->$model->$name = $value;
                return $record;
            } catch (Exception $e) {}
        }
        throw new Doctrine_Record_UnknownPropertyException(sprintf('Unknown record property / related component "%s" on "%s"', $name, get_class($record)));
    }

    public function filterGet(Doctrine_Record $record, $name)
    {
        foreach ($this->_options['relations'] as $model) {
            try {
                return $record->$model->$name;
            } catch (Exception $e) {}
        }
        throw new Doctrine_Record_UnknownPropertyException(sprintf('Unknown record property / related component "%s" on "%s"', $name, get_class($record)));
    }
}

Now you can see this filter checks to see if the property exists on any of the relations specified otherwise throws the normal Doctrine_Record_UnknownPropertyException.

The last thing we need to do is add a magic __call() function to our template to handle the forwarding of any unknown methods to the relations:

<?php
class SharedProperties extends Doctrine_Template
{
    // ...

    public function __call($method, $arguments)
    {
        $invoker = $this->getInvoker();
        foreach ($this->_options['relations'] as $model) {
            try {
                return call_user_func_array(array($invoker->$model, $method), $arguments);
            } catch (Exception $e) {
                continue;
            }
        }
    }
}

This is required if we have functions defined on the models and want to be able to access these methods. So for example if we were to add a setPassword() method to the generated User class like the following:

<?php
class User extends BaseUser
{
    public function setPassword($password)
    {
        $this->_set('password', md5($password));
    }
}

Without the above __call() function we would not be able to do the following:

<?php
$administrator = new Administrator();
$administrator->setPassword('new_password');

**TIP** **Auto Accessor and Mutator Overriding**

If you want Doctrine to automatically override accessors with
matching ``set*()`` and ``get*()`` functions then you need to
enable the ``auto_accessor_override`` attribute in your
configuration where you create your connections and set Doctrine
attributes:
<?php
    $manager = Doctrine_Manager::getInstance();
    $manager->setAttribute('auto_accessor_override', true);

Now with that attribute the following is possible. Instead of
having to call the method ``setPassword()``, Doctrine sees you are
setting the ``password`` and a method named ``setPassword()``
exists so it uses it to do the mutating.
<?php
    $administrator->password = 'new_password';

Example Usage

That is it! Our behavior is implemented and we are ready to write some code that use our new models.

Creating New Records

<?php
$admin = new Administrator();
$admin->name = 'Jonathan H. Wage';
$admin->username = 'jwage';
$admin->password = 'changeme';
$admin->is_active = 1;
$admin->responsibilities = 'Train all the PHP developers!';
$admin->save();

Now that code results in the following structure being persisted to the database:

<?php
print_r($admin->toArray(true));
/*
Array
(
    [id] => 2
    [responsibilities] => Train all the PHP developers!
    [user_id] => 2
    [User] => Array
        (
            [id] => 2
            [username] => jwage
            [password] => 4cb9c8a8048fd02294477fcb1a41191a
            [entity_id] => 3
            [Entity] => Array
                (
                    [id] => 3
                    [name] => Jonathan H. Wage
                    [is_active] => 1
                    [slug] => jonathan-h-wage
                    [created_at] => 2009-02-04 16:01:12
                    [updated_at] => 2009-02-04 16:01:12
                )

        )

)
*/

Data Fixtures

Similarly, the following data fixtures would be possible:

[yml]
BlogPost:
  BlogPost_1:
    name: Test Blog Post
    title: This is a test blog post
    body: This is a test blog post

Administrator:
  Administrator_1:
    name: Test Manager
    username: jwage
    password: changeme
    responsibilities: Overseeing development department

Querying For and Accessing Data

You can query for these relationships as well:

<?php
$q = Doctrine_Query::create()
    ->from('Administrator a')
    ->leftJoin('a.User u')
    ->leftJoin('u.Entity e')
    ->where('u.username = ?', 'jwage');

$user = $q->fetchOne();
echo $user['created_at'];

The above code would output the value of the created_at column that actually exists in the Entity model that is available through the Administrator->User->Entity relations.

]]>
Wed, 04 Feb 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/02/03/doctrine-1-0-7-is-available.html http://www.doctrine-project.org/2009/02/03/doctrine-1-0-7-is-available.html <![CDATA[Doctrine 1.0.7 is Available!]]>

Doctrine 1.0.7 is Available!

Today I have made available Doctrine 1.0.7 , the latest bug fix release for the 1.0 version of Doctrine. This release is a significant one with a few dozen bugs fixed. Below is a list that highlights some of the fixes.

Highlights

  • [r5361] Fixed NestedSet to not create column for root column if it already exists (closes #1817)
  • [r5419] Fixes #1856. Added checking to schema file to ensure correct file extension (format).
  • [r5429] Fixes issue with generated count queries (closes #1766)
  • [r5438] Fixes issue with saveRelated() being called too early (closes #1865)
  • [r5441] Fixing generated models to adhere to coding standard of using 4 spaces (closes #1846)
  • [r5459] Fixes issue with I18n and column aliases (closes #1824)

Lots of other fixes have been made in this release so if you want to see a list of all the changes be sure to check the changelog.

]]>
Tue, 03 Feb 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/01/30/new-documentation-pdf-downloads.html http://www.doctrine-project.org/2009/01/30/new-documentation-pdf-downloads.html <![CDATA[New Documentation PDF Downloads]]>

New Documentation PDF Downloads

Today we have some great news! Thanks to Fabien from the symfony project , we now have a new way to generate the PDF version of our documentation. The new PDFs are a MAJOR step up from the previous style of PDF and am very pleased with it! Check it out by viewing the 1.0 version of The Guide to Doctrine for PHP or The Doctrine Cookbook.

What is next?

  • API Documentation available as PDF.
  • Downloadable package/zip file containing PDF versions of all documentation.
  • User submitted articles, snippets, tutorials, etc. to complement the official documentation.
  • ...Printed book.

Printed Book

Here is a teaser of the first draft of the front cover for the printed version of the book. Big thanks goes out to Jason O’Brien from centre{source} for doing the design work. The printed copy will be available on lulu very soon we just need to do some more proof reading and Q&A on everything before it is ready. The printed version of the book will use a slightly modified version of the PDF that is available for download on the web.

]]>
Fri, 30 Jan 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/01/28/cookbook-recipe-relation-dql-behavior.html http://www.doctrine-project.org/2009/01/28/cookbook-recipe-relation-dql-behavior.html <![CDATA[Cookbook Recipe: Relation DQL Behavior]]>

Cookbook Recipe: Relation DQL Behavior

Today I will teach you how to write a simple Doctrine behavior. You will learn some of the basics of creating a behavior and you will gain some pretty cool functionality for your relationships.

We will write a behavior called RelationDql which allows you to add default query parts that are automatically added to your queries when you reference the specified relationships. So first we will get started by looking at an example schema we can apply this to.

Here is an example schema where we have a Site, BlogPost and Tag model:

[yml]
Site:
  columns:
    name: string(255)

BlogPost:
  actAs: [Timestampable]
  columns:
    title: string(255)
    body: clob
    site_id: integer
  relations:
    Site:
      foreignAlias: BlogPosts
    Tags:
      class: Tag
      refClass: BlogPostTag
      foreignAlias: BlogPosts

Tag:
  columns:
    name: string(255)

BlogPostTag:
  columns:
    blog_post_id:
      type: integer
      primary: true
    tag_id:
      type: integer
      primary: true
  relations:
    BlogPost:
      foreignAlias: BlogPostTags
    Tag:
      foreignAlias: BlogPostTags

This is a fairly simple schema as you can see, but what if we want to have a relationship on the Site model to retrieve the latest five BlogPost records or order the Tags relationship alphabetically by default?

Lets modify our schema to take into account a new behavior that we will write in the next step. First modify the Site model and a relationship named LatestBlogPosts:

[yml]
Site:
  actAs:
    RelationDql:
      relations:
        LatestBlogPosts:
          orderBy: %s.created_at DESC
          limit: 5
  columns:
    name: string(255)
  relations:
    LatestBlogPosts:
      autoComplete: false
      class: BlogPost
      local: id
      foreign: site_id

**TIP** The ``autoComplete`` option is set to ``false`` so that the
relationship is not reflected and added to the opposite end,
``BlogPost`` automatically.

Now lets modify the BlogPost model to change the Tags relationship so that it is ordered alphabetically by name by default:

[yml]
BlogPost:
  actAs:
    Timestampable:
    RelationDql:
      relations:
        Tags:
          orderBy: %s.name ASC
  columns:
    title: string(255)
    body: clob
    site_id: integer
  relations:
    Site:
      foreignAlias: BlogPosts
    Tags:
      class: Tag
      refClass: BlogPostTag
      foreignAlias: BlogPosts

**TIP** The ``relations`` array is an array of changes to make to
the DQL query. The key can be any valid function on the
``Doctrine_Query`` API and the value is of course the parameter to
pass to the function.

Now that we have our schemas modified to take into account the new RelationDql behavior we need to actually write the code:

<?php
class RelationDql extends Doctrine_Template
{
  protected $_options = array();

  public function __construct($options)
  {
    $this->_options = $options;
  }

  public function setTableDefinition()
  {
    $this->_table->addRecordListener(new RelationDqlListener($this->_options));
  }
}

The template is very simple. It only attaches a record listener to the invoking table. Their is where most of the magic happens. So now lets define the RelationDqlListener class:

<?php
class RelationDqlListener extends Doctrine_Record_Listener
{
  protected $_options = array('relations' => array());

  public function __construct($options)
  {
    $this->_options = $options;
  }

  public function preDqlSelect(Doctrine_Event $event)
  {
    $query = $event->getQuery();

    if (empty($this->_options['relations']))
    {
      throw new Doctrine_Exception(
        'You must specify at least one relationship to add DQL to'
      );
    }

    $relations = $this->_options['relations'];

    $components = $this->_getDqlCallbackComponents($query);
    foreach ($components as $alias => $component)
    {
      if (isset($component['relation']) && isset($relations[$component['relation']->getAlias()]))
      {
        $dqls = $relations[$component['relation']->getAlias()];
        foreach ($dqls as $func => $dql)
        {
          $dql = str_replace('%s', $alias, $dql);
          $query->$func($dql);
        }
        unset($relations[$component['relation']->getAlias()]);
      }
    }
  }

  protected function _getDqlCallbackComponents($query)
  {
      $params = $query->getParams();
      $componentsBefore = array();
      if ($query->isSubquery()) {
          $componentsBefore = $query->getQueryComponents();
      }

      $copy = $query->copy();
      $copy->getSqlQuery($params);
      $componentsAfter = $copy->getQueryComponents();

      if ($componentsBefore !== $componentsAfter) {
          return array_diff($componentsAfter, $componentsBefore);
      } else {
          return $componentsAfter;
      }
  }
}

So now we have the behavior defined so lets look at some example DQL queries and the SQL that is outputted:

TIP Remember, in order for the dql callbacks to be executed we must enable an attribute first.
<?php
    $manager->setAttribute('use_dql_callbacks', true);
<?php
$q = Doctrine_Query::create()
  ->select('s.name, p.title, p.created_at')
  ->from('Site s')
  ->leftJoin('s.LatestBlogPosts p');

echo $q->getSql();

The above would output the following SQL:

[sql]
SELECT s.id AS s__id, s.name AS s__name, b.id AS b__id, b.title AS b__title, b.created_at AS b__created_at FROM site s LEFT JOIN blog_post b ON s.id = b.site_id ORDER BY b.created_at DESC LIMIT 5

**NOTE** Notice how the ``ORDER BY`` and ``LIMIT`` were added to
the query.

Now lets look at an example that involves the BlogPost tags:

<?php
$q = Doctrine_Query::create()
  ->from('BlogPost p')
  ->leftJoin('p.Tags t');

echo $q->getSql();

The above would output the following SQL query:

[sql]
SELECT b.id AS b__id, b.title AS b__title, b.body AS b__body, b.site_id AS b__site_id, b.created_at AS b__created_at, b.updated_at AS b__updated_at, t.id AS t__id, t.name AS t__name FROM blog_post b LEFT JOIN blog_post_tag b2 ON b.id = b2.blog_post_id LEFT JOIN tag t ON t.id = b2.tag_id ORDER BY t.name ASC

As you can see the ORDER BY clause to order the related tags by name was added for us.

Pretty cool huh? You can use this in your projects to make your relationships a little nicer.

]]>
Wed, 28 Jan 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/01/26/php-5-3-and-doctrine-2-0-teaser.html http://www.doctrine-project.org/2009/01/26/php-5-3-and-doctrine-2-0-teaser.html <![CDATA[PHP 5.3 and Doctrine 2.0 Teaser]]>

PHP 5.3 and Doctrine 2.0 Teaser

We’ve been really busy around here as you may have noticed. Doctrine 1.1 is about to be released, we just got some much needed new documentation, we’re going to be offering a printed version of the documentation soon! Something we haven’t talked to much about is Doctrine 2.0! Roman has been quietly working on the next major major version of Doctrine, 2.0. This version will be taking a big leap by requiring PHP 5.3! The progress this new version of PHP is so great and it lends itself very well to the world of Object Relational Mappers.

Doctrine 2.0 Teaser

Here is an early teaser of what one of the class meta data drivers looks like:

<?php
namespace Doctrine\Tests\Models\CMS;

/**
* @DoctrineEntity(tableName="cms_articles")
*/
class CmsArticle
{
   /**
    * @DoctrineId
    * @DoctrineColumn(type="integer")
    * @DoctrineIdGenerator("auto")
    */
   public $id;

   /**
    * @DoctrineColumn(type="varchar", length=255)
    */
   public $topic;

   /**
    * @DoctrineColumn(type="varchar")
    */
   public $text;

   /**
    * @DoctrineManyToOne(targetEntity="Doctrine\Tests\Models\CMS\CmsUser",
           joinColumns={"user_id" = "id"})
    */
   public $user;

   /**
    * @DoctrineOneToMany(targetEntity="Doctrine\Tests\Models\CMS\CmsComment", mappedBy="article")
    */
   public $comments;
}

**NOTE**

Notice these few things:

1.) We define the class meta data for the model in the doc block.
This is just one way you will be able to define class meta data.
YAML schema syntax will be possible as well.

2.) The ``CmsArticle`` class is not extending anything! Thats right
in Doctrine 2.0 your domain model won't be imposed on one bit!

3.) The properties on the class are not required to be public, they
can of course be private or protected. Doctrine will not require
you to have a getter and setter methods for every property. It is
totally up to how the user wants to design the class.

Doctrine 2.0 is being built around the concept of a UnitOfWork that keeps track of your objects during a script execution. You just work with your objects normally and when you commit a UnitOfWork, Doctrine takes care of synchronizing your mapped objects with the database, taking care of referential integrity etc. The boundaries of a UnitOfWork can be defined by the user, typically, however, one script execution requires only one UnitOfWork. In Doctrine 2.0 we really try to keep Doctrine out of your domain objects as much as possible, yet providing you with all the features you need.


PHP 5.3 Benchmarks

While I have been playing with Doctrine 2.0 I did some simple benchmarks against the Doctrine 1.0 version test suite to see what kind of performance improvements were made. I was pretty impressed!

These tests are not the best obviously but it does clearly show that when you run the Doctrine tests under PHP 5.3, it is faster and uses less memory.

PHP 5.2.8

# | Seconds | Memory — | ——— | —————– 1 | 24 | 129170.648438 KB 2 | 23 | 129164.078125 KB 3 | 23 | 129176.851562 KB

PHP 5.3.0alpha4-dev

# | Seconds | Memory — | ——— | —————– 1 | 21 | 89858.7421875 KB 2 | 20 | 89864.59765625 KB 3 | 21 | 89867.89453125 KB

The Doctrine test suite uses 31% less memory and is 17% faster when running under PHP 5.3!

]]>
Mon, 26 Jan 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/01/23/introducing-doctrine-orm-for-php.html http://www.doctrine-project.org/2009/01/23/introducing-doctrine-orm-for-php.html <![CDATA[Introducing: Doctrine ORM for PHP]]>

Introducing: Doctrine ORM for PHP

Today I am very happy to announce that we have a first draft available of the new main Doctrine documentation which is titled, “Doctrine ORM for PHP”. The content of this documentation was re-organized and completely re-written from the “Old Manual”. The order of the chapters and sections have been re-thought and we’ve tried to put them in a more logical order. Now you can follow along in the chapters with code exercises and actually play with Doctrine as you read!

Main Highlights

  • Almost 100% re-written.

  • Chapters renamed and reorganized.

  • Chapters split a part in to multiple to ease reading and flow.

  • Added sample Doctrine implementation for executing exercise code as you read.

  • Lots of aesthetic improvements: SQL highlighting, YAML highlighting and better PHP highlighting colors.

    NOTE We also added a few new markups that get rendered as boxes that standout with a representative icon. The three different boxes are: note, tip and caution.

To Do

With this announcement we have a few more things left to do and we need your help!

Perform Week of Revisions

First we need to spend about a week or so proof-reading the the new documentation. This is where the community can really be helpful. Go ahead and create a trac account if you don’t already have one. This way when you’re reading and you spot a problem or have an idea how something could be better you can create a ticket easily.

NOTE The goal here is to get the 1.0 version tightened up and polished with a nice shine! Then we can branch the new documentation for 1.1.

Provide Exercise Code for Download

At the end of each chapter we will provide a tagged copy of the state of the exercise code so you can check your work against ours or if you get behind you can get caught back up by downloading the code.

Release Doctrine 1.1

We have a few more bugs to fix in the 1.1 version then we will release the second stable version of Doctrine, 1.1. Right before we release Doctrine 1.1(which will hopefully also be in a week or so), we will branch the new documentation for 1.1 and make all the necessary updates based on what’s changed. Then we will release and open it to your suggestions.

Printed Book: “Doctrine ORM for PHP”

Once the new documentation has a bit of time to gather some user feedback and typos weeded out we will offer the documentation in a physical printed format through lulu. Don’t worry we will still offer all the documentation for free on the website. Even if you’ve already read the documentation on the web you can show your appreciation for the project and support it by purchasing a copy.

TIP If you want to print a rich text version of the Book yourself instead of using the PDF or ordering a copy, we have implemented a print stylesheet so when you access the documentation here you will get the version styled for printing.

Now go ahead and check out Doctrine ORM for PHP - Guide to Doctrine for PHP and bring me some feedback. :)

]]>
Fri, 23 Jan 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/01/15/documentation-updates.html http://www.doctrine-project.org/2009/01/15/documentation-updates.html <![CDATA[Documentation Updates]]>

Documentation Updates

Enhancements

Over the past few days I have rolled out some changes to the documentation which are mostly aesthetic. Overall the changes make the documentation much richer and easier to read.

Some of the changes made to the documentation are listed below:

  • Added next and previous links to navigate between chapters
  • Adding syntax highlight to YAML examples
  • Added syntax highlighting to SQL/DQL examples
  • Enhanced PHP syntax highlighting colors
  • Added styled caption boxes for notes, tips, sidebars and cautions
  • Other miscellaneous styling enhancements

Why?

Why are we making these enhancements? This is in preparation for a new version of the manual which will be the first piece of documentation on Doctrine available in print! We will release more information about when this will be available soon.

]]>
Thu, 15 Jan 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/01/12/doctrine-1-1-is-right-around-the-corner.html http://www.doctrine-project.org/2009/01/12/doctrine-1-1-is-right-around-the-corner.html <![CDATA[Doctrine 1.1 is right around the corner]]>

Doctrine 1.1 is right around the corner

1.1 Release Manager

First, I would like to introduce Guilherme Blanco as the release manager of Doctrine 1.1. This means he will be responsible for organizing the tickets and managing the releases for the 1.1 branch from now on. So, if you have any issues you can yell at him :)

1.1 Release Candidate

Another great thing today is that we have made available the first release candidate of the 1.1 branch. We were originally planning on having a third beta but as the amount of tickets that came in was practically none, we decided to move on to the release candidate stage.

As always, you can download here and check out the change log and the upgrade document to find out what has changed in 1.1.

]]>
Mon, 12 Jan 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/01/06/2nd-1-1-beta-released.html http://www.doctrine-project.org/2009/01/06/2nd-1-1-beta-released.html <![CDATA[2nd 1.1 Beta Released!]]>

2nd 1.1 Beta Released!

Today we are happy to introduce the 2nd beta version of the 1.1 branch. This means we are getting very close to delivering a stable version to you.

Development Highlights

  • 5311 - Fixed infinite loop problem with isValid()
  • 5336 - Added $deep argument for isValid() and isModified() and defaulted it to false to maintain BC
  • 5337 - Removes used of _identifiers in synchronizeWithArray()
  • 5339 - Reverting 5084 as it introduces some bugs which cannot be fixed until a later version
  • 5341 - Fixed issue with named parameters
  • 5344 - Added checking for obj.field IN :named to prevent possible issues of DQL
  • 5345 - Fixed issue with temporary generated models not being cleaned up properly

You can also check out the detailed documentation of all the changes that are contained in the 1.1 version of Doctrine as well as the changelog to help ease the upgrade process.

]]>
Tue, 06 Jan 2009 00:00:00 +0000
http://www.doctrine-project.org/2009/01/05/doctrine-1-0-6-released.html http://www.doctrine-project.org/2009/01/05/doctrine-1-0-6-released.html <![CDATA[Doctrine 1.0.6 Released]]>

Doctrine 1.0.6 Released

Welcome Back

Don’t worry! Doctrine is alive :) It has been a bit quiet around here due to the holidays. I was able to take a week long vacation and it was very nice being away from everything for the first time in almost three years. I hope everyone enjoyed the holidays as much as I did.

1.0.6 Released

Anyways, on my first day back I am happy to introduce the freshly packaged Doctrine 1.0.6 bug fix release. This release contains dozens of fixes and the change log can be read here. It is strongly encouraged that you upgrade as soon as possible.

Doctrine 1.1

On a side note, we will be releasing the 2nd beta of 1.1 later this week and we have a few other surprises that will be a part of the 1.1 stable release. So, you will have to stick around to see what we have planned. You can check out what is new in 1.1 by reading the upgrade file.

]]>
Mon, 05 Jan 2009 00:00:00 +0000
http://www.doctrine-project.org/2008/12/11/double-dose-of-doctrine.html http://www.doctrine-project.org/2008/12/11/double-dose-of-doctrine.html <![CDATA[Double Dose of Doctrine]]>

Double Dose of Doctrine

Today I am happy to introduce two new versions of Doctrine! We have made available yet another maintenance release for the 1.0 version, 1.0.5. This release contains dozens of fixes that are logged here. In addition to the monthly 1.0.x maintenance release, we have made available the first beta of the 1.1 development branch of Doctrine.

This is exciting news because this means we are very close to releasing a stable version. We just need to work out the last final kinks and we need your help to do it. You can read about what has changed in the upgrade to 1.1 file.

]]>
Thu, 11 Dec 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/12/03/first-1-1-alpha-version-released.html http://www.doctrine-project.org/2008/12/03/first-1-1-alpha-version-released.html <![CDATA[First 1.1 Alpha Version Released]]>

First 1.1 Alpha Version Released

Today I am very happy to introduce the first alpha version of the 1.1 branch of Doctrine. This means we have just about finalized the scope of features and are preparing to enter the beta and release candidate cycles before releasing the stable version.

This new version is sporting dozens of enhancements and even more bug fixes. Primarily the new scalar hydration type , the migration diff tool , and other miscellaneous new features.

You can download the package here and read some documentation on the changes and new features here.

]]>
Wed, 03 Dec 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/11/25/doctrine-1-0-4-released.html http://www.doctrine-project.org/2008/11/25/doctrine-1-0-4-released.html <![CDATA[Doctrine 1.0.4 Released]]>

Doctrine 1.0.4 Released

Today we are happy to introduce the immediate availability of Doctrine 1.0.4. This is a major bug fix release for the 1.0 branch of Doctrine. It contains over 75 bug fixes and it is recommended that you upgrade as soon as possible. As always you can view the change log on the website and download here.

]]>
Tue, 25 Nov 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/10/26/symfony-doctrine-schema-manager.html http://www.doctrine-project.org/2008/10/26/symfony-doctrine-schema-manager.html <![CDATA[symfony Doctrine Schema Manager]]>

symfony Doctrine Schema Manager

As you all probably know, Doctrine has been tightly integrated with a few different PHP frameworks. Since symfony was my choice of framework a few years back, I have dedicated a lot of time towards working on the integration between the two.

Something I’ve always thought would be fun to build and has been one of the most requested items by users is a nice web based interface for managing your schema and generate your models from it. With the new form framework as of symfony 1.1 , you can build rich forms with a nice OOP interface. This made it extremely easy to make the schema manager feature of the sfDoctrineManagerPlugin. It was as simple as automatically generating a set of forms from the schema information data structure inside of Doctrine.

|sfDoctrineManagerPlugin|

This symfony plugin allows you to manage all your schema information from a nice web based interface. You can create new schemas or load your existing schemas to edit. More information about it as well as screen shots can be found here.

]]>
Sun, 26 Oct 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/10/19/the-bleeding-edge-website-upgraded.html http://www.doctrine-project.org/2008/10/19/the-bleeding-edge-website-upgraded.html <![CDATA[The Bleeding Edge: Website Upgraded]]>

The Bleeding Edge: Website Upgraded

This weekend I decided it was time to completely dive in to the awesomeness that is symfony 1.2. I upgraded the Doctrine website to 1.2 as well as Doctrine 1.1. I had several schema changes that I migrated to production with the new Migrations features that were mentioned previously on the blog. It made the upgrade of the website much easier. The primary motivation for diving in to this was a blog post made on 10/18/2008 and 10/14/2008 where Fabien talks about forms in symfony 1.2.

Below is an overview of some of the changes made.

  • Upgraded to symfony 1.2
  • Upgraded to Doctrine 1.1
  • New backend control panel for administering the content of the website
  • Single Sign-On(SSO) - We now have partial SSO. Trac and the main website authentication are shared now. The forum will be integrated soon.
  • New groundwork started for several new website features, new documentation, user contributed documentation, user contributed packages! and more.

Here are some screen shots of the backend magic that was generated by symfony. I didn’t have to do much and in one evening we have a new content management system backend for the website.

Doctrine Releases

The style and custom icons in this list of the available Doctrine releases were added thanks to my custom theme built specifically for the Doctrine backend.

Doctrine Releases

Doctrine Releases

Edit User SVN Access

Thanks to the symfony form framework I was able to easily add a custom widget for editing the website users svn access for all the different Doctrine versions.

Edit User SVN Access

Edit User SVN Access

Doctrine Release Points

List of all the Doctrine sub-release points.

Doctrine Release Points

Doctrine Release Points

Edit Doctrine Release

Edit a Doctrine release and control its stability as well as other information.

Edit Doctrine Release

Edit Doctrine Release

Edit Blog Post

Edit a blog post entry using markdown syntax.

Edit Blog Post

Edit Blog Post

NOTE The source of this website can be downloaded via SVN at http://www.doctrine-project.org/svnweb/trunk
]]>
Sun, 19 Oct 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/10/18/new-to-migrations-in-1-1.html http://www.doctrine-project.org/2008/10/18/new-to-migrations-in-1-1.html <![CDATA[New to Migrations in 1.1]]>

New to Migrations in 1.1

In Doctrine 1.1 migrations are much easier to work with. In addition to the increased stability we have enhanced the migrations in a few ways to simplify the use of them dramatically.

We have introduced the following features.

  • Diff Tool - Generate migration classes by simply changing your schema and generating the migrations.
  • Down Automation - Doctrine now has the ability to automate the down of of a migration call.

Generating Migrations

Imagine you have the following starting schema.

[yml]
---
User:
  columns:
    username: string(255)
    password: string(255)

Build your initial models from the schema.

$ ./doctrine generate-models-yaml

Now we want to enhance our schema to add some new columns as well as a new model with the following schema.

[yml]
---
User:
  columns:
    username: string(255)
    password: string(255)
    email_address: string(255)

Phonenumber:
  columns:
    user_id: integer
    phonenumber: string(25)
  relations:
    User:
      onDelete: CASCADE
      foreignAlias: Phonenumbers

Now by simply changing our schema we can generate the migrations required to upgrade our database.

$ ./doctrine generate-migrations-diff

Now in your migrations directory you will see 3 migration classes created for you.

1224273485_add_user.php

<?php
<?php
/**
 * This class has been auto-generated by the Doctrine ORM Framework
 */
class AddUser extends Doctrine_Migration_Base
{
  public function up()
  {
    $this->createTable('up', 'user', array('id' => array('type' => 'integer', 'length' => 8, 'autoincrement' => true, 'primary' => true), 'username' => array('type' => 'string', 'length' => 255), 'password' => array('type' => 'string', 'length' => 255)), array('indexes' => array(), 'primary' => array(0 => 'id')));
  }

  public function down()
  {
    $this->dropTable('up', 'user');
  }
}

1224273485_version1.php

<?php
<?php
/**
 * This class has been auto-generated by the Doctrine ORM Framework
 */
class Version1 extends Doctrine_Migration_Base
{
  public function up()
  {
    $this->createTable('up', 'phonenumber', array('id' => array('type' => 'integer', 'length' => 8, 'autoincrement' => true, 'primary' => true), 'user_id' => array('type' => 'integer', 'length' => 8), 'phonenumber' => array('type' => 'string', 'length' => 25)), array('indexes' => array(), 'primary' => array(0 => 'id')));
    $this->addColumn('up', 'user', 'email_address', '255', 'string', array ());
  }

  public function down()
  {
    $this->dropTable('up', 'phonenumber');
    $this->removeColumn('up', 'user', 'email_address');
  }
}

1224273486_version2.php

<?php
<?php
/**
 * This class has been auto-generated by the Doctrine ORM Framework
 */
class Version2 extends Doctrine_Migration_Base
{
  public function up()
  {
    $this->addIndex('up', 'phonenumber', 'phonenumber_user_id_user_id', array('fields' => array(0 => 'user_id')));
    $this->createForeignKey('up', 'phonenumber', array('name' => 'phonenumber_user_id_user_id_idx', 'local' => 'user_id', 'foreign' => 'id', 'foreignTable' => 'user', 'onUpdate' => NULL, 'onDelete' => 'CASCADE'));
  }

  public function down()
  {
    $this->removeIndex('up', 'phonenumber', 'phonenumber_user_id_user_id', array('fields' => array(0 => 'user_id')));
    $this->dropForeignKey('up', 'phonenumber', array('name' => 'phonenumber_user_id_user_id_idx', 'local' => 'user_id', 'foreign' => 'id', 'foreignTable' => 'user', 'onUpdate' => NULL, 'onDelete' => 'CASCADE'));
  }
}

Down Automation

In addition to Doctrine being able to generate migrations based on your schema changes, you can now easily automate the down of most methods. The last migration class could be simplified a lot by doing the following.

<?php
<?php
/**
 * This class has been auto-generated by the Doctrine ORM Framework
 */
class Version2 extends Doctrine_Migration_Base
{
  public function migrate($direction)
  {
    $this->addIndex($direction, 'phonenumber', 'phonenumber_user_id_user_id', array('fields' => array(0 => 'user_id')));
    $this->createForeignKey($direction, 'phonenumber', array('name' => 'phonenumber_user_id_user_id_idx', 'local' => 'user_id', 'foreign' => 'id', 'foreignTable' => 'user', 'onUpdate' => NULL, 'onDelete' => 'CASCADE'));
  }
}

Notice that in this example we only have one method named migrate() which receives a direction. Most API methods are easy to automate the opposite down so when migrate is called with $direction = ‘down’ then the index and foreign key will be dropped instead of added.

]]>
Sat, 18 Oct 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/10/13/doctrine-1-0-3-released.html http://www.doctrine-project.org/2008/10/13/doctrine-1-0-3-released.html <![CDATA[Doctrine 1.0.3 Released!]]>

Doctrine 1.0.3 Released!

Today I am happy to introduce another important maintenance release for the increasingly stable Doctrine 1.0. This release contains over 60 closed tickets and 80 changesets. It is recommended that you upgrade your project right away. You can view the 1.0.3 changelog here.

]]>
Mon, 13 Oct 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/10/12/new-hydration-modes-for-doctrine-1-1.html http://www.doctrine-project.org/2008/10/12/new-hydration-modes-for-doctrine-1-1.html <![CDATA[New hydration modes for Doctrine 1.1]]>

New hydration modes for Doctrine 1.1

I would like to announce the addition of two new hydration modes to the 1.1 branch that will be included in the 1.1 release.

  • HYDRATE_SCALAR - flat array where the key is made up of the query component alias + field name. This method offers access to all the same data in a flat array and the hydration process for it is much faster.

  • HYDRATE_SINGLE_SCALAR - Allows you to easily access single value results, bypassing the expensive hydration process.

We feel that they fill an important gap between HYDRATE_NONE and HYDRATE_RECORD/HYDRATE_ARRAY.

You can read more about the new hydration modes in the docs. Starting at “Fetching data”. You can also take a look at the new test case.

We encourage everyone to try them out and give us some feedback. Note that this is a feature preview and the implementation and syntax might change (or not) until the final 1.1 release, depending on how many issues arise and depending on the feedback.

]]>
Sun, 12 Oct 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/10/02/first-symfony-1-1-workshop-in-atlanta-usa.html http://www.doctrine-project.org/2008/10/02/first-symfony-1-1-workshop-in-atlanta-usa.html <![CDATA[First symfony 1.1 workshop in Atlanta, USA]]>

First symfony 1.1 workshop in Atlanta, USA

Three years after the launch of symfony as an Open-Source project, Sensio Labs is very proud to announce its new offices in the USA.

To celebrate, we organize our first symfony training in Atlanta between October 29th and 31th. The training will be based on the latest symfony 1.1 and will be held in Atlanta (at the “1230 Peachtree St N.E. Promenade II”).

This symfony workshop will be given by a symfony expert coming from France and Jonathan Wage, the Doctrine lead developer, and a seasoned symfony developer.??A symfony workshop is an interactive training session during which you will learn how to develop high-quality web applications fast and efficiently with symfony. After three days of symfony immersion, guided by Sensio experts sharing their knowledge and experience, you will know enough techniques and methodology to become fluent in agile web development with symfony. You can find more information and subscribe online on our website.

If you want more information, feel free to contact Nicolas Blin at Nicolas.blin [at] sensio.com.Sensio Labs

Sensio Labs helps its customers with their Internet strategy and develops their applications around the best Open-Source frameworks.

Sensio Labs created symfony a Web application framework in PHP. Sensio Labs plays a major role in the Open-Source world. The company has 10 years of experience in development of high value web applications with more than 500 projects for key accounts in many countries.

]]>
Thu, 02 Oct 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/10/02/doctrine-1-1-development-begins.html http://www.doctrine-project.org/2008/10/02/doctrine-1-1-development-begins.html <![CDATA[Doctrine 1.1 Development Begins]]>

Doctrine 1.1 Development Begins

]]>
Thu, 02 Oct 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/09/30/get-expert-training.html http://www.doctrine-project.org/2008/09/30/get-expert-training.html <![CDATA[Get Expert Training]]>

Get Expert Training

Today I am happy to introduce the first training course offered on Doctrine 1.0. These courses are brought to you by SensioLabs, the creators of the symfony MVC Framework. In addition to the Doctrine courses they offer ones on symfony and PHP. Below is a list of some of the upcoming events that you can register for today!

  • Nov 03: Atlanta, USA (Doctrine 1.0 - English)

  • Sep 24: Paris, France (symfony 1.0 - English)

  • Oct 22: Paris, France (symfony 1.1 - Francais)

  • Oct 22: Montpellier (symfony 1.1 - Francais)

The workshops are a three day event and include lunch everyday, mid-morning and mid-afternoon snacks, a copy of all the presented material on a stick and example code. The workshop runs from 9am - 5pm on the first 2 days and from 9am - 4:30pm on the last day. You can learn more about the available training sessions here.

]]>
Tue, 30 Sep 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/09/23/doctrine-at-latino-ware-2008.html http://www.doctrine-project.org/2008/09/23/doctrine-at-latino-ware-2008.html <![CDATA[Doctrine at LatinoWare 2008]]>

Doctrine at LatinoWare 2008

]]>
Tue, 23 Sep 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/09/18/doctrine-and-symfony-frameworks-collaborating.html http://www.doctrine-project.org/2008/09/18/doctrine-and-symfony-frameworks-collaborating.html <![CDATA[Doctrine and symfony frameworks collaborating]]>

Doctrine and symfony frameworks collaborating

Doctrine has been used by many symfony developers for nearly two years as an externally maintained plugin. This week it became official and Doctrine will be bundled and supported by the symfony core team as of version 1.2 which is slated for late Q4 2008. You can read the full blog article on the symfony-project.org blog.

]]>
Thu, 18 Sep 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/09/11/doctrine-1-0-2-released.html http://www.doctrine-project.org/2008/09/11/doctrine-1-0-2-released.html <![CDATA[Doctrine 1.0.2 Released]]>

Doctrine 1.0.2 Released

Due to a minor regression in 1.0.1 we are releasing 1.0.2 which addresses the issue discovered. The issue was reported and fixed immediately. Big thanks to Adam Huttler for the detailed report which allowed us to fix the issue right away. You can download the new version here or upgrade via pear as usual.

]]>
Thu, 11 Sep 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/09/09/doctrine-1-0-1-released.html http://www.doctrine-project.org/2008/09/09/doctrine-1-0-1-released.html <![CDATA[Doctrine 1.0.1 Released]]>

Doctrine 1.0.1 Released

Today we would like to announce the immediate availability of the first maintenance release of the Doctrine 1.0 branch. This release contains several important bug fixes and we recommend that you upgrade as soon as possible. You can upgrade via pear or download the package here.

]]>
Tue, 09 Sep 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/09/05/doctrine-at-symfony-camp2008.html http://www.doctrine-project.org/2008/09/05/doctrine-at-symfony-camp2008.html <![CDATA[Doctrine at SymfonyCamp2008]]>

Doctrine at SymfonyCamp2008

This year I will be making a presentation on Doctrine at the 2008 SymfonyCamp conference on September 12th and 13th. This is a huge opportunity for the project as we’ll get to spread the word about Doctrine to dozens of symfony developers. Come see me at SymfonyCamp and register today. Slots are filling up fast and registration closes soon so sign up now!

]]>
Fri, 05 Sep 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/09/01/doctrine-1-0-released.html http://www.doctrine-project.org/2008/09/01/doctrine-1-0-released.html <![CDATA[Doctrine 1.0 Released]]>

Doctrine 1.0 Released

Today I am extremely happy to introduce the first stable version of Doctrine, 1.0.0. If you’ve been around for a while, then you know this is a long time coming. We’ve been hard at work on Doctrine for nearly 3 years and it is finally time to release a version we will support with bug fix releases every month. This 1.0 release will be maintained until March 1st 2010. Now we have 1.0, what is next? Below are some highlights of what to expect in the future of Doctrine.

  • Doctrine 2.0 - We’ve been working in trunk on Doctrine 2.0 for quite sometime now and this is the next really big milestone for the project. As we work on 2.0 we will backport things for intermediate major versions(1.1, 1.2, etc.)

  • The Doctrine Company? - We’ll be working on a new side to the Doctrine project for organizing commercial support contracts, trainings, seminars, certifications, training material and much more.

  • Doctrine supported by symfony 1.2 - We will be contributing to the integration process of Doctrine with sfDoctrinePlugin. 1.2 will be the first symfony release to bundle Doctrine and support it.

  • More and Better Documentation - Expect updated documentation as well as some new pieces introduced. Doctrine Book?

What are you waiting for? Download Doctrine 1.0 now and give it a try. Check out the Cookbook and Manual to help you get started. The My First Project Tutorial is good for just getting started and getting your feet wet.

]]>
Mon, 01 Sep 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/08/27/release-candidate-2-available.html http://www.doctrine-project.org/2008/08/27/release-candidate-2-available.html <![CDATA[Release Candidate 2 Available]]>

Release Candidate 2 Available

Only two days after making available the first release candidate we have prepared the second release candidate and made it available for download. This release contains dozens and dozens of bug fixes as well as a few new minor features required to fill some holes/gaps in the 1.0 API before releasing. Below are some highlights of this release.

  • #1077 - Implemented Accessor Overriding

  • #1331 - Implemented orWhere() support to Doctrine_Query API

  • Finished Searchable Behavior API and added Documentation

  • #1319 - Added relationship reverse engineering support for MSSQL

  • Completed Named Query Supportand added Documentation

  • Turned Portability Mode off by Default

  • 100+ changeses/70+ Tickets Closed

We will have one more release candidate on either Friday or Saturday of this week and Doctrine 1.0 Stable will be released Monday September 1st 2008. If you haven’t given the 1.0 branch a try yet, please do so and report any issues to us so that we can get them fixed before Monday. Thanks!

]]>
Wed, 27 Aug 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/08/27/moving-quickly.html http://www.doctrine-project.org/2008/08/27/moving-quickly.html <![CDATA[Moving Quickly]]>

Moving Quickly

Right out of the gate we’re moving extremely fast. Only two days in to working full-time on the project we’ve made some significant pushes forward. On Monday we made available the first 1.0 Release Candidate and then immediately began working on the second and final release candidate. This milestone is extremely significant as it already contains over 70 closed tickets! It will be released either Wednesday or Thursday and 1.0 Stable will follow after it on Monday September 1st. Below are some other highlights on the progress made so far.

Website Updates

New API Documentation Index

New Method Summary List

RC2 Development Highlights

  • Fixed Searchable behavior and added missing Documentation

  • Added Database Reverse Engineering for MSSQL

  • Documented Named Query Support

  • The heavily anticipated orWhere() support has been introduced to Doctrine_Query

  • Dozens of commits and over 70 closed tickets

]]>
Wed, 27 Aug 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/08/25/pre-1-0-updates-and-1-0-0-rc1-released.html http://www.doctrine-project.org/2008/08/25/pre-1-0-updates-and-1-0-0-rc1-released.html <![CDATA[Pre 1.0 Updates and 1.0.0-RC1 Released]]>

Pre 1.0 Updates and 1.0.0-RC1 Released

Today we have a few updates for the project to announce. You can read about whats new below.

Doctrine Release Candidate 1 Released

The first release candidate of Doctrine 1.0 has been made available. Doctrine 1.0 is still scheduled to be released on September 1st 2008. You can download Doctrine here.

New Domain! www.doctrine-project.org

We have decided to ditch the old phpdoctrine.org domain in favor of doctrine-project.org. The main reason is due to licensing complications and us not being technically allowed to have the name PHP in our project name.

Minor Website Ideas

We have updated the website with some minor asthetic changes, primarily to the homepage.

]]>
Mon, 25 Aug 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/08/08/creating-a-unit-of-work-using-doctrine.html http://www.doctrine-project.org/2008/08/08/creating-a-unit-of-work-using-doctrine.html <![CDATA[Creating a Unit of Work Using Doctrine]]>

Creating a Unit of Work Using Doctrine

I am happy to introduce the latest contribution to the 1.0 cookbook, Creating a Unit of Work Using Doctrine by Jon Lebensold. Big thanks to him, he reached out to me wanting to contribute something to the project so he offered to add this great recipe to the cookbook. It properly demonstrates the unit of work pattern for saving and deleting Doctrine objects. If you are interested in contributing to Doctrine, adding something to the cookbook is a great way to help out by only giving 1 hour of your time. Contact me at jonwage [at] gmail.com if you are interested in contributing.

]]>
Fri, 08 Aug 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/08/06/master-and-slave-connections.html http://www.doctrine-project.org/2008/08/06/master-and-slave-connections.html <![CDATA[Master and Slave Connections]]>

Master and Slave Connections

In this new cookbook recipe we demonstrate how you can setup multiple connections and use them as master/slaves. All select statements are issued to the slaves and any insert/update/delete statements are issued to the master. This example accomplishes the functionality by extending Doctrine_Query and Doctrine_Record. This article is a perfect example of how you can extend and override functionality in Doctrine to accomplish your needs when Doctrine doesn’t necessarily have a native solution ready to go for you.

]]>
Wed, 06 Aug 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/08/05/doctrine-1-0-beta1-released.html http://www.doctrine-project.org/2008/08/05/doctrine-1-0-beta1-released.html <![CDATA[Doctrine 1.0 BETA1 Released]]>

Doctrine 1.0 BETA1 Released

Today I am happy to announce the release of Doctrine 1.0-BETA1. This marks the true start for the 1st generation Doctrine stable lifecycle. As you may already know, Doctrine 1.0 has been slated to be released on September 1st 2008 for quite some time now. We still have a few more pre-1.0 releases to go until 1.0. The roadmap for now is BETA1, RC1, RC2 and then 1.0 STABLE. You can see the roadmap in trac if you’re interested in keeping up with the Doctrine schedule. More information on 1.0 and what other things to expect on September 1st will be given soon. Make some noise!

]]>
Tue, 05 Aug 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/07/26/doctrine-growth.html http://www.doctrine-project.org/2008/07/26/doctrine-growth.html <![CDATA[Doctrine growth]]>

Doctrine growth

Last October 2007 we implemented some google analytics to our website to monitor the growth of the community. Today the traffic has about doubled since then. We average around 1000 unique visitors per day up from around 300 roughly 1 year ago. We expect the growth to continue and we look forward what milestones we can reach together in the future. Check out the graph of absolute unique visitors from google analytics below.

]]> Sat, 26 Jul 2008 00:00:00 +0000 http://www.doctrine-project.org/2008/07/25/who-is-behind-doctrine.html http://www.doctrine-project.org/2008/07/25/who-is-behind-doctrine.html <![CDATA[Who is behind Doctrine?]]>

Who is behind Doctrine?

Today I have updated the about page on the website so you can get a glimpse of who is behind the Doctrine project. Each core contributor contains a brief description of themselves and the role they play in the project. Comments are allowed on each contributors profile so please feel free to express your thanks to them there. Follow the doctrine!

]]>
Fri, 25 Jul 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/07/24/taking-advantage-of-column-aggregation-inheritance.html http://www.doctrine-project.org/2008/07/24/taking-advantage-of-column-aggregation-inheritance.html <![CDATA[Taking Advantage of Column Aggregation Inheritance]]>

Taking Advantage of Column Aggregation Inheritance

Today I have published another tutorial in the 1.0 Cookbook. This recipe solves the same situation where you want to allow address properties on multiple records. This approach is a much more normalized implementation compared to using templates/behaviors and it allows for multiple addresses instead of only one. Check it out in the cookbook here. Enjoy!

]]>
Thu, 24 Jul 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/07/21/plug-and-play-schema-information-with-templates.html http://www.doctrine-project.org/2008/07/21/plug-and-play-schema-information-with-templates.html <![CDATA[Plug and Play Schema Information With Templates]]>

Plug and Play Schema Information With Templates

Check out the latest addition to the Doctrine Cookbook. We have added a short little tutorial on how to use Doctrine templates to solve a real world problem to allow Address attributes on many records easily. We will be publishing many more tutorials in the coming weeks. If you’re interested in contributing a tutorial please contact me at jonwage [at] gmail.com.

]]>
Mon, 21 Jul 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/07/20/doctrine-gets-its-first-employee.html http://www.doctrine-project.org/2008/07/20/doctrine-gets-its-first-employee.html <![CDATA[Doctrine gets its first employee]]>

Doctrine gets its first employee

Starting in September 2008, I will begin working full-time on Doctrine! This great opportunity has been allowed by Sensio, the creators of the symfony MVC Framework. This arrangement will allow many great new things to happen for Doctrine. Below you will find a list of some of the things you can look forward to:

  • Core Development

  • The Doctrine Book

  • Travel to conferences

  • Doctrine Evangelism

  • Commercial/Paid Support

  • Workshops

  • Certifications

This is also good news for the symfony project as it is due to officially support Doctrine as its primary ORM in future versions. I will also be helping the core symfony team with the official integration of Doctrine with sfDoctrinePlugin.

]]>
Sun, 20 Jul 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/07/12/doctrine-0-11-1-and-1-0.html http://www.doctrine-project.org/2008/07/12/doctrine-0-11-1-and-1-0.html <![CDATA[Doctrine 0.11.1 and 1.0]]>

Doctrine 0.11.1 and 1.0

Today we have released a new version, 0.11.1. As with all point releases it is a bug fix only release. With over 81 tickets closed, this is definetly a significant release for Doctrine towards 1.0. We recommend that you upgrade.

We have also created the 1.0 branch and will begin actively working on it. We have hit the final straight away towards 1.0! This was originally slated to be the 0.12 branch but we feel it is ready and we will spend the next 2 months furiously working on tickets before we release it on September 1st. We will have some short intermediate BETA and RC releases before then but these will primarily be bug fix releases only. Make some hype please, thanks. ;)

]]>
Sat, 12 Jul 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/07/02/doctrine-1-0-and-symfony-1-2.html http://www.doctrine-project.org/2008/07/02/doctrine-1-0-and-symfony-1-2.html <![CDATA[Doctrine 1.0 and symfony 1.2]]>

Doctrine 1.0 and symfony 1.2

This morning Fabien from the symfony project announced the roadmap for the next major version of symfony, 1.2. He announced that Doctrine would be officially supported as a “first class citizen.” The time couldn’t be better as symfony 1.2 is scheduled to be released in October and Doctrine is slated to release 1.0 around the same time. This is good news for Doctrine, symfony and more importantly PHP in general. I look forward to seeing what comes of all this in the coming months.

]]>
Wed, 02 Jul 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/07/01/introducing-the-doctrine-forum.html http://www.doctrine-project.org/2008/07/01/introducing-the-doctrine-forum.html <![CDATA[Introducing the Doctrine Forum]]>

Introducing the Doctrine Forum

For those of you who are not keen on using the mailing list or irc for getting help with Doctrine, we now have a public Forum, powered by PHPBB3(which is very nice btw). Please contact me at jonwage at gmail.com if you would like a forum for your language added or if you are interested in being a moderator.

]]>
Tue, 01 Jul 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/06/29/1000th-ticket-closed.html http://www.doctrine-project.org/2008/06/29/1000th-ticket-closed.html <![CDATA[1000th Ticket Closed]]>

1000th Ticket Closed

Tonight I have closed the 1000th ticket in the Doctrine Trac. This is a big milestone for Doctrine and it has taken the work of many people to reach this. Thanks to all the users who took the time to report issues to us (test case or not ;) ), it is much appreciated and Doctrine would not be able to move forward without it.

]]>
Sun, 29 Jun 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/06/24/0-11-0-stable-released.html http://www.doctrine-project.org/2008/06/24/0-11-0-stable-released.html <![CDATA[0.11.0 Stable Released]]>

0.11.0 Stable Released

Today, I would like to introduce the latest stable version of Doctrine, 0.11.0. This release is a major release but it contains bug fixes only. It contains a few BC enhancements that were required in order to fix some bugs. We recommend everyone upgrade to 0.11. Below are some highlights of this release.

  • 131 Tickets Closed

  • [4433] Introduced preDql*() Hooks

  • Introduced SoftDelete Behavior

  • Introduced Application Level Cascading Deletes

  • Many fixes to Behavior system, primarily Nesting Behaviors.

Another item worth mentioning about the 0.11 release is that the integration between Doctrine and symfony has evolved quite well over the first quarter of 2008 as symfony 1.1 is coming out and 0.11 is released. The integration between symfony 1.1 and Doctrine with sfDoctrinePlugin is now officially supported by the symfony core team and we will slowly be introducing more documentation over the coming months.

]]>
Tue, 24 Jun 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/06/23/introducing-the-doctrine-cookbook.html http://www.doctrine-project.org/2008/06/23/introducing-the-doctrine-cookbook.html <![CDATA[Introducing the Doctrine Cookbook]]>

Introducing the Doctrine Cookbook

Today I would like to introduce something new to the Doctrine documentation, the Cookbook. This differs from the manual in that it will contain real world examples and tutorials of how you can use Doctrine on a daily basis whereas the manual is more of a technical breakdown of the features in Doctrine. We will be publishing many additions to the cookbook in the coming weeks. To start off we have published the following tutorials:

  • My First Project

  • symfony 1.1 and Doctrine

  • symfony 1.1 and Doctrine Migrations

  • Code Igniter and Doctrine

If you are interested in contributing to the Doctrine documentation by adding new things or translations please contact me at jonwage@gmail.com.

]]>
Mon, 23 Jun 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/06/21/doctrine-in-your-language.html http://www.doctrine-project.org/2008/06/21/doctrine-in-your-language.html <![CDATA[Doctrine in your language]]>

Doctrine in your language

I have been waiting for this day for some time, the day we have the manual in a 2nd language. For many months the website has been capable of handling multiple languages but the features have not been exposed until now. Thanks to Masaki and Takeshi, two very experienced Japanese symfony + Doctrine developers, we now have the Doctrine manual available in Japenese. The primary text of the website will also be translated in the following weeks. If you are interested in having the Doctrine website and manual in your language, please contact me so we can make arrangements for you to have access to easily provide translations.

]]>
Sat, 21 Jun 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/06/16/getting-started-with-doctrine-and-symfony-1-1.html http://www.doctrine-project.org/2008/06/16/getting-started-with-doctrine-and-symfony-1-1.html <![CDATA[Getting started with Doctrine and symfony 1.1]]>

Getting started with Doctrine and symfony 1.1

Today, over on the symfony-project blog. A short tutorial on how to get started using Doctrine and symfony 1.1 has been published. As of symfony 1.1, Doctrine is officially supported by symfony and this is the first step of many to make Doctrine the default ORM in symfony. Over the coming months, much of the symfony + Propel documentation will be ported to work with Doctrine. The tutorial can be read here.

]]>
Mon, 16 Jun 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/06/13/php-net-style-api-documentation-lookups.html http://www.doctrine-project.org/2008/06/13/php-net-style-api-documentation-lookups.html <![CDATA[Php.net style API documentation lookups]]>

Php.net style API documentation lookups

I have been using php.net style API lookups ever since I can remember. It is very nice being able to simply go to http://php.net/array_walk and have it pull up that function in the PHP API Documentation. So, tonight i have implemented this functionality in to the Doctrine website. Below are some examples of how you can quickly access the API docs for a specific function or class.

]]>
Fri, 13 Jun 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/06/11/one-more-0-11-release-candidate.html http://www.doctrine-project.org/2008/06/11/one-more-0-11-release-candidate.html <![CDATA[One more 0.11 Release Candidate]]>

One more 0.11 Release Candidate

Well, we discovered some bugs in the last RC of 0.11 so we have decided to have another release candidate to make sure the 0.11 branch is a solid major release of Doctrine. As always the changelog can be read in the CHANGELOG in svn or on the website. Hopefully this will really be the last release candidate of 0.11 and we will release a stable version. Once 0.11 is released we plan to immediately begin working on 0.11.1 bug fix release as well as a new 0.12 branch which will bring some new features as well as dozens of bug fixes. Thanks for all the contributions from the core developers and community for this release.

]]>
Wed, 11 Jun 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/05/31/0-11-0-rc3-released.html http://www.doctrine-project.org/2008/05/31/0-11-0-rc3-released.html <![CDATA[0.11.0-RC3 Released]]>

0.11.0-RC3 Released

A little late, but the third release candidate of the 0.11.0 version of Doctrine has been released. This will be the last scheduled release candidate before 0.11 becomes the latest stable version of Doctrine. This release contains dozens of bug fixes and a few small enhancements. The change log can be read here.

]]>
Sat, 31 May 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/05/11/road-to-doctrine-1-0.html http://www.doctrine-project.org/2008/05/11/road-to-doctrine-1-0.html <![CDATA[Road to Doctrine 1.0]]>

Road to Doctrine 1.0

First I would like to thank everyone who has adopted Doctrine and stuck with us through the many long and difficult development iterations. Though we have many more, and potentially even more difficult iterations to get through for Doctrine 2.0, we now see the end of the tunnel for Doctrine 1.0. I have laid out the official roadmap for 1.0 and it can be viewed on trac here. The planned release date of Doctrine 1.0 is September 1st 2008, which is also my 23rd birthday, and Doctrine 2.0 will follow it exactly one year later on September 1st 2009.

]]>
Sun, 11 May 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/05/03/website-upgraded-to-symfony-1-1-and-doctrine-0-11.html http://www.doctrine-project.org/2008/05/03/website-upgraded-to-symfony-1-1-and-doctrine-0-11.html <![CDATA[Website upgraded to symfony 1.1 and Doctrine 0.11]]>

Website upgraded to symfony 1.1 and Doctrine 0.11

Today I have upgraded the Doctrine website to symfony 1.1 and Doctrine 0.11. The integration between the symfony framework and Doctrine with sfDoctrinePlugin has become pretty complete in the last few days. It now has all the same functionality as the bundled sfPropelPlugin with symfony 1.1 plus dozens more features a long with the Doctrine DBAL and ORM. The main features introduced to the symfony framework are migrations, DQL, behaviors, inheritance and a sprinkle of additional admin generator features. I have also completely re-ported sfGuardDoctrinePlugin from sfGuardPlugin so it is in sync with it and has exactly the same features, nothing more. The removed functionality will be moved to separate plugins that work with sfGuardDoctrinePlugin.

The source of the Doctrine website can be gotten from svn here http://www.phpdoctrine.org/svnweb

]]>
Sat, 03 May 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/04/30/wow-1000-tickets.html http://www.doctrine-project.org/2008/04/30/wow-1000-tickets.html <![CDATA[Wow! 1000 tickets]]>

Wow! 1000 tickets

Last night the 1000th ticket came rolling in. This is just a reminder to the fact that Doctrine while still young, has had a very long and evolutionary life so far. The growth this first quarter in the community and contributions from all over the world really shows that Doctrine has a bright future in PHP and I look forward to seeing all the doors that Doctrine will open. Thanks everyone!

]]>
Wed, 30 Apr 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/04/30/0-11-0-release-candidate-2.html http://www.doctrine-project.org/2008/04/30/0-11-0-release-candidate-2.html <![CDATA[0.11.0 Release Candidate 2]]>

0.11.0 Release Candidate 2

Quick! Come and get it! The second release candidate of the latest Doctrine version, 0.11.0, has just been released. This release includes a few dozen fixed tickets and a few new features required in order to address existing issues/tickets. The complete changelog as always can be found in the CHANGELOG file included with the source or online here.

]]>
Wed, 30 Apr 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/04/21/0-11-0-release-candidate-1.html http://www.doctrine-project.org/2008/04/21/0-11-0-release-candidate-1.html <![CDATA[0.11.0 Release Candidate 1]]>

0.11.0 Release Candidate 1

Today I am happy to announce the first release candidate for the next major version of Doctrine, 0.11. The 0.11 version of Doctrine brings over 50 addressed tickets, a few new features, a few performance improvements and lots of updates to the documentation/manual.

Here are the highlights:

  • *Table.php classes are no longer generated by default when generating models from an existing database schema. This also means that ATTR_AUTOLOAD_TABLE_CLASSES now defaults to FALSE

- Fixed some serious hydration bugs.

- Improved the hydration performance for large (joined) result sets.

- Application-level cascading deletes are back.

We encourage everyone to test this release candidate thoroughly. Please report any issues through trac.

You can view the complete changelog for this release here.

]]>
Mon, 21 Apr 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/04/05/doctrine-frequently-asked-questions.html http://www.doctrine-project.org/2008/04/05/doctrine-frequently-asked-questions.html <![CDATA[Doctrine frequently asked questions]]>

Doctrine frequently asked questions

We have compiled a new addition to the Doctrine website, Frequently Asked Questions. The purpose of this is to help the users of Doctrine identify any common questions/problems when using Doctrine. I have added all the questions I have encountered multiple times over the last year+. If you have any recommendations for this least please don’t be shy and let us know. Thanks.

]]>
Sat, 05 Apr 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/04/01/doctrine-goes-pecl.html http://www.doctrine-project.org/2008/04/01/doctrine-goes-pecl.html <![CDATA[APRIL FOOLS! Doctrine goes PECL]]>

APRIL FOOLS! Doctrine goes PECL

After many long debates and countless hours of development, Doctrine has been successfully ported to a PECL extension and will be maintained as a PECL extension from now on. The extension can be downloaded and installed via PEAR. As a PECL extension the ORM performs 4 times as fast and brings unbelievable results. Enjoy!

]]>
Tue, 01 Apr 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/03/29/using-doctrine-zend-framework.html http://www.doctrine-project.org/2008/03/29/using-doctrine-zend-framework.html <![CDATA[Using Doctrine with Zend Framework]]>

Using Doctrine with Zend Framework

Today, “rubenv” pinged me in IRC and told me he has put together an article on how to get started using Doctrine with the Zend Framework. The article is very simple and does not get in to the detailed usage of Doctrine, but it shows you how you to integrate the two frameworks together and even shows a very simple web application. The article can be found here.

]]>
Sat, 29 Mar 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/03/28/0-10-4-released-46-closed-tickets.html http://www.doctrine-project.org/2008/03/28/0-10-4-released-46-closed-tickets.html <![CDATA[0.10.4 Released - 46 Closed Tickets]]>

0.10.4 Released - 46 Closed Tickets

Today we would like to announce the 0.10.4 release. This release addresses 46 tickets and is a major step in stabilizing the 1st generation of Doctrine for the 1.0 release. We will continue with bug fix only releases until we feel the 0.10 branch is ready for a 1.0 title. Give it a try and give us some tickets and failing test cases to fix :)

You can checkout the change log for the 0.10.4 release as well as previous releases here.

]]>
Fri, 28 Mar 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/03/18/0-10-3-released.html http://www.doctrine-project.org/2008/03/18/0-10-3-released.html <![CDATA[0.10.3 Released]]>

0.10.3 Released

A few days late, but the 0.10.3 release has been packaged and released. This release contains nearly 40 closed tickets, and is a huge step towards bringing the 1st generation of Doctrine to a stable release. We have already begun development on the 0.10.4 release, and have a few dozen tickets associated to it already. If you have a ticket associated to the 0.10.4 milestone or any other release then it is likely their is not a failing test case for it, as the 0.10 branch now only has 1 failing test case. Make our job easier and provide a failing test case for your issues. Thanks.

]]>
Tue, 18 Mar 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/03/16/4-000th-svn-commit-revision.html http://www.doctrine-project.org/2008/03/16/4-000th-svn-commit-revision.html <![CDATA[4,000th svn commit/revision]]>

4,000th svn commit/revision

This evening Doctrine reached a milestone of four thousand commits in svn. Doctrine has maintained steady development for almost three years strong, and we feel this milestone is very significant for the evolution of Doctrine. Today, we would like to announce that the first generation of Doctrine, also know as 0.10, will be the first real candidate for the first(second) stable 1.0 version. After 3 point releases of the 0.10 branch we have fixed over 100 tickets, and made huge steps towards the first stable release of Doctrine. Several months ago, we decided to make a feature freeze as 0.9 branch, so that we could continue on going refactorings to Doctrine while providing a stable branch for our users. Now, several months later, we have evolved to 0.10 and are beginning to become more and more stable. We have also decided that the developments in trunk are so significant that they deserve a title of Doctrine 2.0, the second generation of Doctrine.

Now, we need some help from our users. The 0.10 branch is down to one failing test case(soon to be fixed). With over 100 unfixed tickets, and 1 failing test case, this means we need some failing test case writing done :) As I’ve said before, the best way to ensure your issue is fixed, is to create a failing test case replicating the issue. You can read about how to write test cases for the 0.10 branch here.

]]>
Sun, 16 Mar 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/03/04/doctrine-cheat-sheet.html http://www.doctrine-project.org/2008/03/04/doctrine-cheat-sheet.html <![CDATA[Doctrine Cheat Sheet]]>

Doctrine Cheat Sheet

I have put together a cheat sheet for all the day to day usage syntaxes of Doctrine. The cheat sheet can be found here. This is the first draft of the document so any comments and feedback would be very useful.

]]>
Tue, 04 Mar 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/03/02/my-first-project-doctrine-tutorial.html http://www.doctrine-project.org/2008/03/02/my-first-project-doctrine-tutorial.html <![CDATA[My First Project Doctrine Tutorial]]>

My First Project Doctrine Tutorial

I have put together a short and sweet tutorial on how to get started using Doctrine in under 5 minutes. A few weeks ago, we announced the sandbox package which allows you to get started using Doctrine with a zero configuration sandbox environment. The tutorial is built using this sandbox package and shows you how Doctrine can be easily implemented and used in your web applications.

]]>
Sun, 02 Mar 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/03/01/0-10-2-released.html http://www.doctrine-project.org/2008/03/01/0-10-2-released.html <![CDATA[0.10.2 Released]]>

0.10.2 Released

Today we have released Doctrine 0.10.2. This is a bug fix only release. It brings many new bugs fixes to the 0.10 branch. We will continue with point releases on the 0.10 branch until the 0.9 branch is completely phased out. Thanks for using Doctrine :)

]]>
Sat, 01 Mar 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/02/18/doctrine-orm-sandbox.html http://www.doctrine-project.org/2008/02/18/doctrine-orm-sandbox.html <![CDATA[Doctrine ORM Sandbox]]>

Doctrine ORM Sandbox

Today I would like to announce the official introduction of the Doctrine sandbox package. The Doctrine sandbox was first introduced in SVN a few months ago, but is now available as a downloaded package. Every major release of Doctrine has a sandbox available for it. The sandbox is a sample implementation of Doctrine that is ready to be used with zero configuration. It comes configured with a sqlite database so it requires that you have pdo sqlite enabled on your server. The packages can be downloaded here. I have also put together a small wiki page on how you can get started using the sandbox to easily play with Doctrine. The wiki page can be found here.

]]>
Mon, 18 Feb 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/02/16/doctrine-0-9-1-0-10-1-released.html http://www.doctrine-project.org/2008/02/16/doctrine-0-9-1-0-10-1-released.html <![CDATA[Doctrine 0.9.1 / 0.10.1 Released]]>

Doctrine 0.9.1 / 0.10.1 Released

Today the Doctrine team is proud to announce the release of Doctrine 0.9.1 and 0.10.1. Both releases bring many fixes and a few minor additions for missing features in each of the branches. The next release of 0.10.2 will replace the 0.9 branch and all users will be recommended to upgrade as the 0.9 branch will no longer be supported and maintained by the core dev team. We except that 0.10.2 is due in two to three weeks. Please upgrade your existing projects from 0.9 to 0.10 and let us know what issues you come across when switching so we can ensure a smooth migration from 0.9 to 0.10 for all of our users.

On a side note, many new changes have been made to the website. A few visual things and a few functional things. You will now find on the Download page you can now get Doctrine in either zip or tgz format. We also have our very own PEAR server so you are able to install Doctrine via the pear command line interface. Our channel is located at pear.phpdoctrine.org and can be discovered by running ‘pear channel-discover pear.phpdoctrine.org’

]]>
Sat, 16 Feb 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/02/14/doctrine-all-grown-up.html http://www.doctrine-project.org/2008/02/14/doctrine-all-grown-up.html <![CDATA[Doctrine all grown up]]>

Doctrine all grown up

Over the past several months, Doctrine has done some growing up. While the code has been under constant development for over 2 years, it hasn’t been until the last 6 months that Doctrine has gotten a proper home and infrastructure to support the growth of the project over the coming years. Some of the things we’ve been able to accomplish are listed below:

  • Standardized svn and trac urls to svn/trac.phpdoctrine.org

  • Brand new design and official logo by Phu Son

  • Setup donation collections for the Doctrine project

  • Migrated doctrine.pengus.net to phpdoctrine.org permanently

  • Initiated proper package/release branch management to ensure stability for our users

  • And of course continuing development towards 1.0

All these things are great for the project and we hope it serves the project well in the long run. Now we have some plans from today on. Soon we will begin to phase out the 0.9 branch completely and it will be replaced with the 0.10 branch. In the coming days we will release 0.9.1 and 0.10.1. The next release after that will be 0.10.2 and the 0.9 branch will officially not be supported any longer. Everyone will be recommended to upgrade to 0.10.2. On another note, trunk development towards 1.0 has been furious in the past month or so. Romanb has spearheaded the re factorings required to bring Doctrine to the level required for a 1.0 release. We will continue developing in trunk towards 1.0 while maintaining the 0.10.x branch bringing you bug fixes daily.

]]>
Thu, 14 Feb 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/01/29/using-doctrine-with-codeigniter.html http://www.doctrine-project.org/2008/01/29/using-doctrine-with-codeigniter.html <![CDATA[Using Doctrine with CodeIgniter]]>

Using Doctrine with CodeIgniter

If you use the PHP MVC framework, CodeIgniter, and want to use Doctrine, here is a tutorial on how to integrate Doctrine with your CodeIgniter applications. It was fairly simple and took me about 15 minutes to figure out a nice and clean implementation. The wiki page can be found here.

]]>
Tue, 29 Jan 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/01/25/a-few-updates-for-2008.html http://www.doctrine-project.org/2008/01/25/a-few-updates-for-2008.html <![CDATA[A few updates for 2008]]>

A few updates for 2008

Some of these announcements are a little late but I think they deserve a proper announcement.

First, we have setup a way for you to give us all your money :) Please feel free to give a little. The purpose of the Doctrine donation collection is simple. The creators of Doctrine don’t work on this great product for any money. The contributions are made out of the pure enjoyment of working on a great open source project such as Doctrine. It is not totally clear what exactly the donations will be used for now, but in the future they may be used to fund infrastructure expenses required by the project, sending developers to conferences, marketing, or even split amongst the developers of Doctrine. So if you or your company uses Doctrine and are happy with it, a donation to further the project would be much appreciated.

Secondly, we have made some updates to the website. Specifically the Download page. It now has proper links to packages and svn for each release of Doctrine. These packages are generated nightly from the source in svn.

Finally, as some of you all may already know, we have finally gotten our release/package management under control and you can expect stability in the area of releases, branches and BC breaks!

]]>
Fri, 25 Jan 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/01/16/cleaning_up_the_mess.html http://www.doctrine-project.org/2008/01/16/cleaning_up_the_mess.html <![CDATA[Cleaning up the mess]]>

Cleaning up the mess

Starting from last blog post, development team went under some general discussions to reach a commom sense regarding the project versions. We are finally organizing our project from a non-versioned stage to a versionable stage, which was causing a lot troubles to everyone. Currently we are under heavy development to reach a stable version of 1.0 release. Until here, we are under some internal refactorings and we decided to create a branch which we named 1.0beta2. Since then, we got a feature freeze version and without big refactorings. The trunk went under big changes and we decided to not keep the 1.0beta2 as the branch name; we renamed it 0.10. We know it is a big impact for those that checked-out the branch, but we think it is safer to do it now instead of have to deal with versions confusion in a near future. It’s the best organization we can reach and it’s the last one (thanks God!). Now that we have the branches 0.9 and 0.10, it is time to define minor versions. We caught from our history what was the first release of 0.9 and we tagged it as 0.9.0. We also got the old 1.0beta2 release and tagged it as 0.10-beta2. So currently we have 2 commit-free tagged versions and 2 branches with feature freeze. We highly discourage users from using trunk, since it is a very unstable environment and your code may not work. Please update your repository locations. These are the changes we did: tags/1.0beta1 => tags/0.9.0 tags/1.0beta2 => tags/0.10-beta2 branches/1.0beta2 => branches/0.10 branches/0.9 => no change We also schedule new tagged releases in a near future. The next releases will be 0.9.1 and 0.10-rc1. You can join #doctrine channel (at irc.freenode.net) or group list to follow discussions regarding this subject. We apologize the mess we caused to users until now and we hope to not have this problem again, specially because we didn’t have much release management knowledge. Thanks.

]]>
Wed, 16 Jan 2008 00:00:00 +0000
http://www.doctrine-project.org/2008/01/05/project_status.html http://www.doctrine-project.org/2008/01/05/project_status.html <![CDATA[Project Status]]>

Project Status

Here is a short update on the current project status. We’re heavily developing towards a 1.0 release that will bring lots of enhancements like improved inheritance mapping and lots of other stuff. We’re especially keen on making this release as stable as possible and on polishing the documentation.

Until then we strongly encourage everyone to use the 0.9 branch that can be found here: http://svn.phpdoctrine.org/branches/0.9 It’s a feature-frozen branch that recieves bugfixes. There will be no changes that break backwards compatibility in this branch.

The current trunk is under heavy development, so please don’t use it unless you are developing on Doctrine’s source code or you are just very curious.

When the time for the 1.0 release comes near we will provide a migration guide and do everything possible to help you take the leap from 0.9 to 1.0.

PS: At this point, the the whole Doctrine team wants to apologize for the version mess you’ve gone through (and are still getting through). We really messed up in terms of release management mainly due to the lack of experience in this area. This stops here. 0.9 will stay and it will stay for a while. We’re not going to rush releases again.

Thank you very much.

]]>
Sat, 05 Jan 2008 00:00:00 +0000
http://www.doctrine-project.org/2007/12/08/new_design.html http://www.doctrine-project.org/2007/12/08/new_design.html <![CDATA[New Design]]>

New Design

Thanks to Phuson we have a brand new design that is absolutely spectacular. Now we have a design that is on the same level of Doctrine itself. We all owe him a big thanks.

]]>
Sat, 08 Dec 2007 00:00:00 +0000
http://www.doctrine-project.org/2007/12/04/url_changes.html http://www.doctrine-project.org/2007/12/04/url_changes.html <![CDATA[URL Changes]]>

URL Changes

Recently we have done some work to sort out our domain names and the permanent URL structure we will use from now on. We have put rules in place to maintain all existing URLs so they redirect to www.phpdoctrine.org, trac.phpdoctrine.org and svn.phpdoctrine.org. You will need to update your svn externals to point to svn.phpdoctrine.org.

]]>
Tue, 04 Dec 2007 00:00:00 +0000
http://www.doctrine-project.org/2007/12/03/beta2_released.html http://www.doctrine-project.org/2007/12/03/beta2_released.html <![CDATA[Beta 2 Released]]>

Beta 2 Released

On Friday November 30th, the second beta release of the PHP5 Doctrine ORM software was released. A lot of progress has been made since the first beta(formerly known as RC1). Dozens and dozens of tickets have been fixed, new features have been added, much needed re-factorings have taken place and the community behind Doctrine is growing daily.

]]>
Mon, 03 Dec 2007 00:00:00 +0000
http://www.doctrine-project.org/2007/11/02/beta-2.html http://www.doctrine-project.org/2007/11/02/beta-2.html <![CDATA[Beta 2]]>

Beta 2

The Doctrine team is proud to announce that we have scheduled the release of the second beta snapshot for November 31st, 2007. This is very exciting news for the Doctrine team and community.

This means Doctrine is nearing a real release candidate :) As you all know, we had a RC1 that was released a little while back, but it was a mistake to call it an RC since we planned on still making many changes that would break BC. We have corrected ourselves and renamed it Beta1. We will continue with beta releases until we are comfortable with releasing a true RC1.

]]>
Fri, 02 Nov 2007 00:00:00 +0000
http://www.doctrine-project.org/2007/10/14/new-coverage-report.html http://www.doctrine-project.org/2007/10/14/new-coverage-report.html <![CDATA[New Coverage Report]]>

New Coverage Report

The Doctrine development team are pleased to announce the release of a coverage report system. Special things to meus and romanb for thier work in this area.

The report can be seen at http://doctrine.pengus.net/doctrine/trunk/tests/coverage/index.php. This new report will help to ensure that the Doctrine code is well tested, ensuring that the upcomming doctrine version 1 release is well tested and stable.

]]>
Sun, 14 Oct 2007 00:00:00 +0000
http://www.doctrine-project.org/2007/10/09/new-website.html http://www.doctrine-project.org/2007/10/09/new-website.html <![CDATA[New Website]]>

New Website

As you all may have noticed, we have put up an actual website. The manual, api documentation, and trac are now all available from the same interface/design. However, the design you see now is only temporary and a new design will be implemented in the near future. We have also added the ability to comment on manual chapters/sections, blog posts, and api documentation classes.

]]>
Tue, 09 Oct 2007 00:00:00 +0000