Preview of next release (0.7)

19 views
Skip to first unread message

Alvaro Carrasco

unread,
Jan 21, 2009, 1:03:22 AM1/21/09
to Outlet ORM
Fellow outlet users,

I have been working hard on the next release of outlet. Since a lot of
the changes I was making were sort of experimental, I created a branch
to work on them: the 'many-to-many' branch.

The main features are:
* One-to-one and many-to-many relationships
* PHP-5.2's DateTime support
* Fluent-interface query API
* Eager fetching

The code currently passes the unit tests, but I feel it still needs some
polish.

There is one BC-incompatible change that was necessary to implement
many-to-many relationships without creating a linking entity in code:
Collections.

On this new version, relationship methods that currently return an array
of entities will now return a Collection object. This object implements
extends ArrayObject so it can be used in most situations where an array
can be used. Here is an example:

<?php

// entities should now be defined like this
class Project {
private $bugs;
...
public function getBugs () {
return $this->bugs;
}
public function setBugs(Collection $bugs) {
$this->bugs = $bugs;
}
...
}
// notice that you no longer need the addBug() method

...

$bugs = $project->getBugs();

// bugs is an instance of Collection
// but it behaves just like an array

// you can call count it
echo count($bugs);

// and you can use it in a foreach
foreach ($bugs as $bug) {
echo $bug->Description;
}

// to add a bug to a project
$bug = new Bug;
$bug->Title = 'Test Bug';

// you no longer need an addBug method
$project->getBugs()->add($bug);

// bug if you create it, you can still use it just the same
$project->addBug( $bug );

?>

Everything else works the same.

I would really appreciate any feedback on these changes, so if you're
adventurous, please check it out:

svn://knowledgehead.com/outlet/branches/many-to-many

Thanks,
Alvaro

Diogo Silva

unread,
Jan 21, 2009, 8:16:11 PM1/21/09
to outle...@googlegroups.com
Alvaro,

In a quick try It passed my projects unit tests without problems, but
I still don't use any of the new features.

2009/1/21 Alvaro Carrasco <alv...@epliant.com>:

Alvaro Carrasco

unread,
Jan 22, 2009, 4:33:10 PM1/22/09
to outle...@googlegroups.com
Hi Diogo,

Diogo Silva wrote:
> Alvaro,
>
> In a quick try It passed my projects unit tests without problems, but
> I still don't use any of the new features.
>

Great, Thanks for checking it out.

In the next few days I'll try to update the documentation and I'll
describe the new features in more details.

> ...

Thanks,
Alvaro

Fabio R.

unread,
Jan 26, 2009, 1:43:31 PM1/26/09
to outle...@googlegroups.com
The other thing I found out is that the OutletMapper::insert method is not calling OutletMapper::saveManyToMany, it is only called in OutletMapper::update method.

Is it meant to work this way?


--
Fábio Rehm


On Mon, Jan 26, 2009 at 3:39 PM, Fabio R. <fgr...@gmail.com> wrote:
Hi Alvaro,

Just got back from vacation and started to try the many-to-many association but I couldn't find out how to configure and use it. I don't know how to create the config file and implement the entities classes.

Could you please send us a simple example of how it is done?


Thanks,
--
Fábio Rehm

Fabio R.

unread,
Jan 26, 2009, 1:39:07 PM1/26/09
to outle...@googlegroups.com
Hi Alvaro,

Just got back from vacation and started to try the many-to-many association but I couldn't find out how to configure and use it. I don't know how to create the config file and implement the entities classes.

Could you please send us a simple example of how it is done?


Thanks,
--
Fábio Rehm


On Thu, Jan 22, 2009 at 6:33 PM, Alvaro Carrasco <alv...@epliant.com> wrote:

Fabio R.

unread,
Jan 27, 2009, 2:03:24 AM1/27/09
to outle...@googlegroups.com
I promise this is the last message (at least until tomorrow :-)

I'm sending this message just to let you guys know that entities with composite integer keys and eager fetching for many-to-one associations are working fine (I haven't tested one-to-one and many-to-many yet) and that I found some other issues testing and looking around the code.


I found out that OutletMapper does not care about 'OutletCollection::removeAll()' when calling 'OutletMapper::saveOneToMany', only on 'OutletMapper::saveManyToMany'.


I didn't get the many-to-many associations to work yet but I think 'OutletMapper::saveManyToMany' is not considering 'plural' configuration since it is just appending a 's' to the foreign name instead of calling 'OutletConfig::getGetter' and 'OutletConfig::getSetter' (line 238 of OutletMapper.php is an example).


On line 126 of OutletQuery there should be a line break after creation of WHERE clause so it doesn't interfere on other clauses:
        if ($this->query)         $q .= 'WHERE ' . $this->query; // Should be $q .= 'WHERE ' . $this->query."\n";
        if ($this->orderby)     $q .= 'ORDER BY ' . $this->orderby . "\n";
        if ($this->limit)         $q .= 'LIMIT ' . $this->limit . "\n";


Still in OutletQuery, I think it would be nice to have a offset parameter as well so we can create pagination. My fix will work for MySQL and PostgreeSQL but not for MS SQL Server so we would need to check the dialect before building the query.
       if ($this->query)         $q .= 'WHERE ' . $this->query . "\n";
       if ($this->orderby)     $q .= 'ORDER BY ' . $this->orderby . "\n";
       if ($this->limit){
            $q .= 'LIMIT '.$this->limit;
            if ($this->offset)
                $q .= ' OFFSET '.$this->offset;
       }
Here is how it is done on SQL Server 2005: http://www.singingeels.com/Articles/Pagination_In_SQL_Server_2005.aspx.
This will probably cause some significant changes to the method but maybe we could use a subclass for SQL Server queries. The dialect could be checked on 'Outlet::from' method so that we wouldn't care about what type is used.


I spent the whole day playing with the library new features and I think it's about time to call it a day :-)
Alvaro, if you agree with me on those points I can commit the changes I've done so far tomorrow morning.
--
Fábio Rehm

Fabio R.

unread,
Jan 26, 2009, 5:59:10 PM1/26/09
to outle...@googlegroups.com
Hey Alvaro,

Sorry for sending so many messages but I found some other issues...


The first is a little bug when INSERTING an object that has Date / DateTime properties.
Around line 359 of OutletMapper.php:
        foreach ($insert_props as $key=>$p) {
            // skip the defaults
            if ($insert_defaults[$key]) continue;

            $values[] = $obj->$p;
        }
This doesn't work because the DateTime object is not being formatted. I get an error saying "Object of class DateTime could not be converted to string".
Here's my fix:
        foreach ($insert_props as $key=>$p) {
            // skip the defaults
            if ($insert_defaults[$key]) continue;

            $values[] = self::toSqlValue( $properties[$p], $obj->$p ); // Based on update method
        }



The other thing I found out is that after inserting an object that has a one-to-many association the object inside the collection is not being updated.
Around line 181 of OutletMapper.php:
            foreach ($children->getLocalIterator() as $child) {
                $child->$key = $pks[0];
               
                self::save($child);
            }
           // If you call print_r($children) here you'll see that the objects weren't updated
This loop is working with a copy of $child. The object will be saved but the collection won't have the object replaced by the corresponding proxy.
Here's my fix:
            foreach (array_keys($children->getArrayCopy()) as $k) {
                $children[$k]->$key = $pks[0];
                self::save($children[$k]);
           }

I found this bug after doing something like this:
    $bug1 = new Bug;
    $bug1->Title = 'Test Bug';                                                                         
    $project->getBugs()->add($bug1);
   
    $outlet->save($project);
   
    $bug2 = new Bug;
    $bug2->Title = 'Test Bug 2';                                                                         
    $project->getBugs()->add($bug2);
   
    $outlet->save($project);


Do you want me to commit the fixes I've done or you have a better approach? I can also create a test for them.


The last thing I noticed is that eager fetching is not working with one-to-many associations because it is calling the 'setter' method instead of Collection::add() but I couldn't figure out how it should be implemented because we need to navigate the result set to get all objects of the collection at once, otherwise the parent object will be added to the returning array more than once (line 159 of OutletQuery.php).
Let me know if you don't understand this point and I'll try to provide some examples for it.


I'm using the lastest version from 'many-to-many' branch.

Thanks for your time and keep up with the good job :-)
--
Fábio Rehm

Alvaro Carrasco

unread,
Jan 27, 2009, 2:39:47 AM1/27/09
to outle...@googlegroups.com
WOW! Thanks for all the feedback. Keep it coming :)

I haven't had a lot of time today, I'll try to reply to all of these
tomorrow. Send me what you want as username and password and I can send
you a commit svn account.

Thanks a lot for all the time you've spent checking it out and looking
at these issues, it was exactly what I was hoping for.

Alvaro

Fabio R.

unread,
Jan 27, 2009, 11:35:03 AM1/27/09
to outle...@googlegroups.com
You've already set up an account for me :-)

Here's all the things I've done:
 - Created OutletQuery::offset parameter / method to support pagination together with OutletQuery::limit
 - Modified OutletMapper::insert method to make it call OutletMapper::saveManyToMany (please check out if I did in the right order, I called after saveOneToMany).
 - Fixed a bug in OutletMapper::insert when inserting entities with Date / DateTime properties (modified to call 'toSqlValue' method for casting values).
 - Modified OutletMapper::saveOneToMany to consider OutletCollection::removeAll()
 - Fixed a bug in OutletMapper::saveOneToMany. The method wasn't updating collection objects to the corresponding proxy.

Still pending:
 - Eager fetch for one-to-many and many-to-many. I had a quick look at Doctrine and NHibernate source but couldn't figure out what they've done, maybe tonight I'll take another look.
 - Implementation for OutletQuery::limit and OutletQuery::offset for MS SQL. If you like the idea of subclassing I can do that.
 - When we get the one-to-many and many-to-many eager fetching to work we'll need to refactor OutletQuery::limit and OutletQuery::offset again since data will come 'denormalized'. (If you don't understand this point I can provide an example)
 - Unit tests (I'll try to do that tonight)


I'll try the library on PostgreSQL and I let you guys know what happens.
I'm looking forward to test many-to-many associations.

See ya,
--
Fábio Rehm

Alvaro Carrasco

unread,
Jan 30, 2009, 10:27:41 AM1/30/09
to outle...@googlegroups.com
Hi Fabio,

Fabio R. wrote:
> You've already set up an account for me :-)
>

Whoops, I forgot, cool.

> Here's all the things I've done:
> - Created OutletQuery::offset parameter / method to support pagination
> together with OutletQuery::limit
> - Modified OutletMapper::insert method to make it call
> OutletMapper::saveManyToMany (please check out if I did in the right order,
> I called after saveOneToMany).
> - Fixed a bug in OutletMapper::insert when inserting entities with Date /
> DateTime properties (modified to call 'toSqlValue' method for casting
> values).
> - Modified OutletMapper::saveOneToMany to consider
> OutletCollection::removeAll()
> - Fixed a bug in OutletMapper::saveOneToMany. The method wasn't updating
> collection objects to the corresponding proxy.
>

Very nice. I see that you committed these, excellent. I'll add you to
the website as a developer.

> Still pending:
> - Eager fetch for one-to-many and many-to-many. I had a quick look at
> Doctrine and NHibernate source but couldn't figure out what they've done,
> maybe tonight I'll take another look.
> - Implementation for OutletQuery::limit and OutletQuery::offset for MS SQL.
> If you like the idea of subclassing I can do that.
> - When we get the one-to-many and many-to-many eager fetching to work we'll
> need to refactor OutletQuery::limit and OutletQuery::offset again since data
> will come 'denormalized'. (If you don't understand this point I can provide
> an example)
> - Unit tests (I'll try to do that tonight)
>

I'll have to look at these in more detail tomorrow.

>
> I'll try the library on PostgreSQL and I let you guys know what happens.
> I'm looking forward to test many-to-many associations.
>
> See ya,
> --
> Fábio Rehm
>

Thanks,
Alvaro

Pavel Arnošt

unread,
Feb 2, 2009, 7:02:42 AM2/2/09
to Outlet ORM
Hi,

i have a feature request for 0.7 release. Can we integrate a very
simple fix that adds transparent accessor/mutator access to class
fields? It's based on Diogo Silva's idea and it consists of adding two
static methods to OutletMapper class and replacing "$obj->$key"
statements with methods calls.

static function objGet($prop, $obj){
$getter = "get{$prop}";

if (method_exists($obj, $getter)) {
return $obj->$getter();
} else {
return $obj->$prop;
}
}

static function objSet($prop, $value, $obj) {
$setter = "set{$prop}";

if (method_exists($obj, $setter)) {
return $obj->$setter($value);
} else {
$obj->$prop = $value;
}
}

Any objections?

Alvaro Carrasco

unread,
Feb 2, 2009, 10:09:22 PM2/2/09
to outle...@googlegroups.com
Hi Pavel,

Not at all, the original message from Diogo just got lost with all the
other stuff (sorry, Diogo). I'll implement this on the trunk in the next
few days.

Thanks,
Alvaro

Reply all
Reply to author
Forward
0 new messages