I attended the great symfony day 09 in cologne yesterday. It was an awesome conference with nice people, interesting talks and discussions.
Propel is dead
One thing got crystal clear during the talks. Propel is dead! In the next version 1.3 of symfony Doctrine will be the default orm. If thats not a hint … In symfony 2.0 Propel will be deprecated. Additionally the “leader of Propel” stated out that he is no longer leading Propel.
So its time to move to Doctrine. The new features in Doctrine 1.2 described by Jonathan Wage are quite nice. And Doctrine 2.0 will be even more impressive.
Sadly it will require a lot of work rewriting Propel “criteria queries” with Doctrine’s DQL-queries. But I’m certain that this step makes my applications future prove.
Default values rule!
I’m using Propel 1.2 (an upgrade will be done soon) but for other people out there …
Consider the following declaration-fragment for the “Foo-entity”. Nothing special here.
<column name="name" type="VARCHAR" size="32" required="true" />
<column name="culture" type="CHAR" size="5" required="true" default="de_DE" />
Now if we create the new object and show the state (
var_dump) of the object the
culture-field is set to ‘de_DE’ which is correct.
$inst = new Foo();
But if you look in your (debug-)logfiles you will see that the
insert-query will be generated as:
INSERT INTO foo (NAME) VALUES ('Foobar')
Where is the value for the culture column?
Propel keeps track of the modified columns to reduce the size of the
update/insert-queries. The default values for the object will not be set through the generated class-methods. Instead the default values are directly assgined in the member-variable of the generated class. So Propel is unaware that the values has changed.
protected $culture = 'de_DE';
I don’t know if this bug is fixed in Propel 1.3. Soon I will know …
As I will continue working with Propel 1.2 in the current project the “workaround” is to manually set the culture. This is best done in the constructor of your derived class. So Propel knows that the column is modified.
class Foo extends BaseFoo
public function __construct()
// Note: The generated base-class does not have a constructor
// so parent::__construct will fail!
Propels (Creole) “criteria infrastructure” is a great speed-up for the development process and makes it easy to “write” queries. However if you are forced to create a SQL-Join which requires multiple join-conditions the criteria-api is not a helper anymore.
In order to make use of the criteria-api even in this case a “hack” can be used. Someone else described it in a blog-post.
$c = new Criteria();
$c->addJoin(Object1Peer::ID, Object2Peer::ID .
' AND ' . Object1Peer::LOCALE . ' = ' . Object2Peer::LOCALE .
' AND ' . Object1Peer::WHATEVER . ' = ' . Object2Peer::WHATEVER,
Its a “hack” but you are not required to write the whole sql-query on your own and can rely on the criteria-api.
As I found out the Propel-developers are aware of this problem and a solution is planned for the (hopefully soon) next Propel release 1.4.
Symfony makes heavy use of Propel. Propel finds objects in the storage container using criteria. If you want to let Propel (okay the database) ignore the case you can set this in the criteria.
$c = new Criteria ();
// Allow case sensitive searches
// Find all posts which name contains propel
$c->add (BlogPostPeer::NAME, 'Propel');
$posts = BlogPostPeer::doSelect ($c);
Because PostgreSQL (unlike MySQL) does not support collations to easily manage how comparisons of strings are done Propel has to generate this sql-statement.
SELECT blog_posts.name, blog_posts.DATE
WHERE UPPER(blog_posts.name) = 'PROPEL';
Depending on your amount of data this can become very slow even if you have an index defined for the "name"-column.
The trick is to create another index for the column "name".
CREATE INDEX "UpperNameIndex" ON blog_posts USING BTREE (UPPER(name));
Thats it. When now using
setIgnoreCase its fast again.