New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Introducing data-mapper and unit of work. #795

Closed
wants to merge 27 commits into
base: master
from

Conversation

Projects
None yet
@marcj
Member

marcj commented Oct 29, 2014

Welcome to the real future of Propel2.

This pull request is rather large and is going to introduce a heavy change in the way Propel 2 works internally and externally.
We announced in several blog posts some years ago a more strictly decoupling of domain model logic and the actual persistent logic, so we support having POPO’s as model classes. The whole architecture is now based on no static methods anymore. The only static method used is to provide active-record facility.

This implements now such a decoupling with the extraction of the logic, we had injected in the object classes directly before, into Repository and Persister class through small peaces called Components. Generated code that is related to a actual persisting method has been moved to the Builders at Platform classes which can modify all builded classes. The glue together is through the UnitOfWork class.

With this decoupling I also decoupled SQL and Propel, so in the future it’s easier to support noSQL databases and even PHPCR.

How this works

Using POPO’s means using a instance of UnitOfWork which knows everything about living objects. It’s kinda the same as in doctrine, but more compatible to Hibernate’s way of doing it.

You have a $configuration object which knows anything about the connection and known DatabasesMaps. It creates also the necessary unitOfWork (called Session) to be used in your user land code.

We have now more builder classes:

  • ActiveRecordTraitBuilder
    This is new. It creates the trait for each model which can be used to activate
    active-record on a entity.
  • EntityMapBuilder
    Old TablMapBuilder. Creates the class with all mapping information and
    highly optimized methods used in persister and formatter classes.
  • ObjectBuilder
    The actual entity class builder, which is reduced to the absolut basics.
  • QueryBuilder
    No big change to old QueryBuilder except the splitting of those extremely
    big classes in several handy peaces (Components).
  • RepositoryBuilder
    This is new. It implements basically the repository pattern also known
    in Doctrine, which provides some basic methods to retrieve objects and handle
    objects. It also contains the methods which were before in the object model itself behavior methods.

The ObjectBuilder generates the really basic entity class with injected trait of the ActiveRecordTraitBuilder if active-record is enabled. RepositoryBuilder generates a new base class <EntityName>Repository which should be mainly used in controllers instead of static stuff of query::create(), means we have now $repository->createQuery().

What changed?

Schema

Through the decoupling of SQL it’s necessary to remove all workflow based on RDBMS, which means:

  1. Renamed <table> to <entity>
  2. entity:name refers now to the PHP Class name instead of the SQL table name.
  3. Renamed <column> to <field>
  4. field:name refers now to the PHP property name instead of the SQL column name.
  5. Renamed <foreign-key> to <relation>
  6. foreign-key > reference is now optional. If not defined but is necessary
    (in case of RDBMS) it is automatically mapped to the Primary Key of the
    foreign entity.
  7. <relation> has now a field attribute instead of a phpName.

Configuration

platformClass moved to since we support now several different database vendors at the same time. It makes no sense to provide a —-platform option to build all models with the same platform, because it would generate the wrong code for entities using different platforms. (imagine a database for mysql and a database for mongodb).

Entity class

The actual entity class does not have any parent class anymore. At wish a active-record trait is injected or can be used to provide active-record methods like save(), delete() etc. This is completely optional. Lazy loading is achieved through a Proxy class, which will be returned in case the entity instance is created through database queries. The entity class contains basically only the properties and getter and setter methods.

Implementation details are hidden now per default. Means if you have a relation from Car to Brand then Car doesn’t have a property brand_id nor its setter and getter method, but only brand.

Code generation

I’ve basically deleted all those extremely big builder classes and started from scratch, copying peace for peace if needed into separat component classes. I also
created several traits which help you as component author with some handy methods which were in the AbstractBuilder classes before (which was too big as well).

To achieve this I’ve also introduced a OOP way of generating PHP classes, methods, properties and so on. It looks like:

$this->addMethod('isNew')
    ->addSimpleParameter('entity', $entityClassName)
    ->setType('boolean')
    ->setDescription("Returns true if this is a new (not yet saved/committed) instance.")
    ->setBody($body);

It generates PHPdoc blocks as well automatically. Double definition of methods are the past with this, although it’s possible to overwrite it acidentely through using incompatible behaviors that generate the same method. However, it’s now possible to detect easier if a method has been declared already or not.

screen shot 2014-10-29 at 14 58 26

Also the builder classes itself are now incredible slim:

class EntityMapBuilder extends AbstractBuilder
{
    /**
     * @param string $injectNamespace
     *
     * @return string
     */
    public function getFullClassName($injectNamespace = '', $classPrefix = '')
    {
        $injectNamespace = 'Map';

        if ($this->getGeneratorConfig() &&
            $customNameSpace = $this->getBuildProperty('generator.objectModel.namespaceMap')) {

            $injectNamespace = $customNameSpace;
        }

        return parent::getFullClassName($injectNamespace) . 'EntityMap';
    }

    public function buildClass()
    {
        $this->getDefinition()->declareUses(
            '\Propel\Runtime\Propel',
            '\Propel\Runtime\EntityMap'
        );
        $this->getDefinition()->setParentClassName('\Propel\Runtime\Map\EntityMap');

        $this->applyComponent('EntityMap\\Constants');
        $this->applyComponent('EntityMap\\ColConstants');
        $this->applyComponent('EntityMap\\GetRepositoryClassMethod');
        $this->applyComponent('EntityMap\\InitializeMethod');
        $this->applyComponent('EntityMap\\BuildRelationsMethod');
        $this->applyComponent('EntityMap\\BuildFieldsMethod');
        $this->applyComponent('EntityMap\\BuildSqlBulkInsertPartMethod');
        $this->applyComponent('EntityMap\\HasAutoIncrementMethod');
        $this->applyComponent('EntityMap\\GetAutoIncrementFieldNamesMethod');
        $this->applyComponent('EntityMap\\PopulateAutoIncrementFieldsMethod');
        $this->applyComponent('EntityMap\\PopulateDependencyGraphMethod');
        $this->applyComponent('EntityMap\\PersistDependenciesMethod');
        $this->applyComponent('EntityMap\\GetPropReaderMethod');
        $this->applyComponent('EntityMap\\GetPropWriterMethod');
        $this->applyComponent('EntityMap\\PopulateObjectMethod');
        $this->applyComponent('EntityMap\\IsValidRowMethod');
        $this->applyComponent('EntityMap\\AddSelectFieldsMethod');
    }
}

Unit of Work

The unit of work pattern is living in Runtime\Session\Session class and provides us now finally the session-per-request pattern. Active-record is still session-per-operation since each save() call creates a new session and database transaction.
Compared to doctrine it’s similar, except the fact that we highly utilize the unit of work pattern to gain extremely more performance. For example we use not a simple topological sort based on mapping information (like doctrine) but a grouped topological sort based on the actual living entity instances. This gives us the ability to fire bulk INSERTs and in general more optimized queries. Compared to doctrine we gained with our unit of work 5 times faster execution times (for 10k inserting rows with simple relation). See benchmark chapter. I’m using this library https://github.com/marcj/topsort.php to sort anything by entity dependencies and grouping by equal type allowing us to have bulk insert/update.

Repository

The repository pattern gives us the ability to hook during runtime into entity lifecycle events. We have events like pre/post save/update/insert/commit. In a behavior you can still inject code into those events by just returning actual php code in the old behavior hook method. However, it’s sometimes handy to hook during runtime in some events, which is now possible. The $configuration has those event dispatcher - you can hook into all events there as well, which aren’t bound then to any repository/entity.

Examples

<database name=“mongo” platform=“mongodb”>
    <entity name=“MyBundle\Model\User”>
        <field name=“id” autoIncrement=“true” primaryKey=“true”/>
        <field name=“name” type=“varchar”
        <relation name=“group” target=“MyBundle\Model\Group” />
    </entity>
    <entity name=“MyBundle\Model\Group”>
        <field name=“id” autoIncrement=“true” primaryKey=“true”/>
        <field name=“name” type=“varchar”
    </entity>
</database>
<database name=“default” platform=“mysql” namespace=“System/Model/”>
    <entity name=“Page”>
        <field name=“id” autoIncrement=“true” primaryKey=“true”/>
        <field name=“title” type=“varchar”/>
        <relation name=“content” target=“Content” />
    </entity>
    <entity name=“Content”>
        <field name=“id” autoIncrement=“true” primaryKey=“true”/>
        <field name=“name” type=“text” />
    </entity>
</database>
// create the $configuration manually 
$configuration = new Configuration(‘./path/to/propel.yml’);
//or through `config:convert` command
$configuration = includegenerated-conf.php’;

$session = $configuration->createSession(); //which is basically done by a framework on each request or controller call
$car = new Car(‘Ford Mustang’);
$session->persist($car); //same as in doctrine’s EntityManager::persist
$session->commit(); //same as in doctrine’s EntityManager::flush
$carRepository = $configuration->getRepository(‘\Car’); //provided usually per services/DI.

$car = $carRepository->find(23);

$brand = new Brand(‘Ford’);
$car->setBrand($brand);

$session->persist($brand);
$session->persist($car);
$session->commit();
//or
$car->save(); //cascade save as usual.
$cars = $carRepository->createQuery()
    ->filterByTitle('bla')
    ->limit(5)
    ->find();

foreach ($cars as $car) {
    $car->setBla('x');
    $session->persist($car);
}

$session->commit();

Why not just use Doctrine

Because we have now a much more simple way of defining entities and we are incredible much more faster during code generation and fully utilizing the unit of work pattern. Also we have way less magic in our classes.
Doctrine's UnitOfWork has 3.000 LOC, we only 100, although this will increase to few hundreds because of the missing circular references check.

Benchmark

propel2-vs-doctrine2

Compatibility

Static creation of query classes are still possible. It uses the same static global configuration object as active record instances. This means the test suite with all its static invokations will still be compatible.

ToDo

[x] Implement Fetch
[ ] Implement lazy loading completely
[x] Implement INSERT
[x] Implement UPDATE (almost done)
[x] Implement DELETE
[ ] Implement circular references persisting fallback
[ ] Convert more behavior to new architecture
[ ] Implement Annotations support
[ ] Make test suite green again
[ ] More tests for repository and unitOfWork

I'm working on it now since some weeks and it will take some weeks. I hope to get some stuff done during the symfony conf.

@willdurand

This comment has been minimized.

Show comment
Hide comment
@willdurand

willdurand Oct 29, 2014

Member

@marcj interesting work in progress! You should probably write clear commit messages though..

One suggestion: do not call Repository something that is certainly not a repository. The repository pattern Keep the Query name.

A Repository mediates between the domain and data mapping layers, acting like an in-memory domain object collection. Client objects construct query specifications declaratively and submit them to Repository for satisfaction.

http://martinfowler.com/eaaCatalog/repository.html

More comments soon.

Member

willdurand commented Oct 29, 2014

@marcj interesting work in progress! You should probably write clear commit messages though..

One suggestion: do not call Repository something that is certainly not a repository. The repository pattern Keep the Query name.

A Repository mediates between the domain and data mapping layers, acting like an in-memory domain object collection. Client objects construct query specifications declaratively and submit them to Repository for satisfaction.

http://martinfowler.com/eaaCatalog/repository.html

More comments soon.

@hhamon

This comment has been minimized.

Show comment
Hide comment
@hhamon

hhamon Oct 29, 2014

Member

Interesting work, well done! I can't wait to play with it.

Member

hhamon commented Oct 29, 2014

Interesting work, well done! I can't wait to play with it.

@marcj

This comment has been minimized.

Show comment
Hide comment
@marcj

marcj Oct 29, 2014

Member

yeah, I will rebase it later and fix some typos in the pr description. The repository used here is actually exactly what you pastet although its not yer fully implemented.

Member

marcj commented Oct 29, 2014

yeah, I will rebase it later and fix some typos in the pr description. The repository used here is actually exactly what you pastet although its not yer fully implemented.

$distfinder = new Finder();
$distfinder->in($dirs)->depth(0)->files()->name($fileName . '.{php,inc,ini,properties,yaml,yml,xml,json}.dist');
$distfiles = iterator_to_array($distfinder);
$distFinder = new Finder();

This comment has been minimized.

@staabm

staabm Oct 29, 2014

Member

IMO you should try to avoid such kind of CS changes.. the diff will be already huge and hard to review because of the changes in a lot of places all over the lib

@staabm

staabm Oct 29, 2014

Member

IMO you should try to avoid such kind of CS changes.. the diff will be already huge and hard to review because of the changes in a lot of places all over the lib

This comment has been minimized.

@marcj

marcj Oct 29, 2014

Member

IMHO some few CS changes shouldn't hurt in a PR that has several ten thousand line changes.

@marcj

marcj Oct 29, 2014

Member

IMHO some few CS changes shouldn't hurt in a PR that has several ten thousand line changes.

@staabm

This comment has been minimized.

Show comment
Hide comment
@staabm

staabm Oct 29, 2014

Member

the whole change makes a lot of sense and will propel2 bring up to a new level. great job so far.

Member

staabm commented Oct 29, 2014

the whole change makes a lot of sense and will propel2 bring up to a new level. great job so far.

@fzaninotto

This comment has been minimized.

Show comment
Hide comment
@fzaninotto

fzaninotto Oct 29, 2014

Member

Interesting work. A few remarks:

  • I don't understand the difference between the Query and the Repository classes. Getting rid of Peer classes was the one big benefit of Propel2, I don't think you need to generate more than 2 classes per entity.
  • I see that objects still have a save() method. How do they get the UnitOfWork instance?
  • Could you show examples of generated Entity/ActiveRecord/Repository code? It's hard to tell if you're heading in the right direction otherwise.
  • The code of the PR is too large to get even a slightest look. Your commit messages are meaningless. This make reviewing impossible, and basically means that this will be a one man project. I'm strongly worried by this.
  • Many of the people who use Propel actually don't like Doctrine and EM, for many reasons (verbosity, magic, need to carry the em everywhere, proxies, DQL, POPO). This major change will probably make Propel lose them. Do you have an idea of how many would stay?
  • I'm surprised to see that PR at a time where Propel 2.0 is almost ready. This will delay the release of the 2.0 a great deal, and to me, this means the death of Propel (not enough progress in stable releases). I advise you to finish Propel 2.0 first, using the architecture that was decided before (i.e. do not change the AR and AQ API, just get rid of Peer classes), then work on this new architecture for Propel 3.0.
Member

fzaninotto commented Oct 29, 2014

Interesting work. A few remarks:

  • I don't understand the difference between the Query and the Repository classes. Getting rid of Peer classes was the one big benefit of Propel2, I don't think you need to generate more than 2 classes per entity.
  • I see that objects still have a save() method. How do they get the UnitOfWork instance?
  • Could you show examples of generated Entity/ActiveRecord/Repository code? It's hard to tell if you're heading in the right direction otherwise.
  • The code of the PR is too large to get even a slightest look. Your commit messages are meaningless. This make reviewing impossible, and basically means that this will be a one man project. I'm strongly worried by this.
  • Many of the people who use Propel actually don't like Doctrine and EM, for many reasons (verbosity, magic, need to carry the em everywhere, proxies, DQL, POPO). This major change will probably make Propel lose them. Do you have an idea of how many would stay?
  • I'm surprised to see that PR at a time where Propel 2.0 is almost ready. This will delay the release of the 2.0 a great deal, and to me, this means the death of Propel (not enough progress in stable releases). I advise you to finish Propel 2.0 first, using the architecture that was decided before (i.e. do not change the AR and AQ API, just get rid of Peer classes), then work on this new architecture for Propel 3.0.
@stood

This comment has been minimized.

Show comment
Hide comment
@stood

stood Oct 29, 2014

good job !

stood commented Oct 29, 2014

good job !

@fzaninotto

This comment has been minimized.

Show comment
Hide comment
@fzaninotto

fzaninotto Oct 29, 2014

Member

Also, your branch isn't testable, so there is no way to see the generated code.

/marcj-data-mapper> ./tests/bin/phpunit.sqlite.sh
Tests started in temp /var/folders/89/v_c0zh856r5d2m1b0d4cmsm00000gn/T.
PHPUnit 4.3.4 by Sebastian Bergmann.

Configuration read from /Users/francois/git/Propel2/phpunit.xml.dist

PHP Fatal error:  Call to undefined method gossi\codegen\model\PhpMethod::addSimpleDescParameter() in /Users/francois/git/Propel2/src/Propel/Generator/Builder/Om/Component/Query/Constructor.php on line 25
Member

fzaninotto commented Oct 29, 2014

Also, your branch isn't testable, so there is no way to see the generated code.

/marcj-data-mapper> ./tests/bin/phpunit.sqlite.sh
Tests started in temp /var/folders/89/v_c0zh856r5d2m1b0d4cmsm00000gn/T.
PHPUnit 4.3.4 by Sebastian Bergmann.

Configuration read from /Users/francois/git/Propel2/phpunit.xml.dist

PHP Fatal error:  Call to undefined method gossi\codegen\model\PhpMethod::addSimpleDescParameter() in /Users/francois/git/Propel2/src/Propel/Generator/Builder/Om/Component/Query/Constructor.php on line 25
@tayhimself

This comment has been minimized.

Show comment
Hide comment
@tayhimself

tayhimself Oct 29, 2014

As a user and fan of Propel, I have to agree with @fzaninotto above regarding finishing Propel 2 first and then push this new stuff in a 2.x or 3.0 release. It has been way too long since the documentation on the propel web site is all about v 2.0 but v 2.0 is nowhere to be found.
Never mind that I can't use 2.0 because the decision to support PHP 5.4.+ means ruling out the very recent CentOS 6.5 (ok enough grumbling!).

tayhimself commented Oct 29, 2014

As a user and fan of Propel, I have to agree with @fzaninotto above regarding finishing Propel 2 first and then push this new stuff in a 2.x or 3.0 release. It has been way too long since the documentation on the propel web site is all about v 2.0 but v 2.0 is nowhere to be found.
Never mind that I can't use 2.0 because the decision to support PHP 5.4.+ means ruling out the very recent CentOS 6.5 (ok enough grumbling!).

@marcj

This comment has been minimized.

Show comment
Hide comment
@marcj

marcj Oct 29, 2014

Member

I don't understand the difference between the Query and the Repository classes. Getting rid of Peer classes was the one big benefit of Propel2, I don't think you need to generate more than 2 classes per entity.

I haven't yet fully defined the use case of repository, but it should act as middle man. Query classes are only there to fire custom queries directly at the underlying database, bypassing unitofwork and all events (if you use ->update or ->delete)

I see that objects still have a save() method. How do they get the UnitOfWork instance?

See

At wish a active-record trait is injected or can be used to provide active-record methods like save(), delete() etc

It uses the global configuration, as currently in Propel 2.

Could you show examples of generated Entity/ActiveRecord/Repository code? It's hard to tell if you're heading in the right direction otherwise.

"right direction" defined by whom?

The code of the PR is too large to get even a slightest look. Your commit messages are meaningless. This make reviewing impossible, and basically means that this will be a one man project. I'm strongly worried by this.

Indeed, they are meaningless. They weren't meant to have meaning just for me as backup commits. I've rebased it now. Btw, it's already almost a one man project.

Many of the people who use Propel actually don't like Doctrine and EM, for many reasons (verbosity, magic, need to carry the em everywhere, proxies, DQL, POPO). This major change will probably make Propel lose them. Do you have an idea of how many would stay?

I really know the benefits of Propel over Doctrine, that's the reason why it's almost compatible. As you see the schema definition became even easier for relations. If you use optional active-record then it behaves almost the same like at the moment, so you don't need to know anything about "em".

I'm surprised to see that PR at a time where Propel 2.0 is almost ready. This will delay the release of the 2.0 a great deal, and to me, this means the death of Propel (not enough progress in stable releases). I advise you to finish Propel 2.0 first, using the architecture that was decided before (i.e. do not change the AR and AQ API, just get rid of Peer classes), then work on this new architecture for Propel 3.0.

I won't develop on a library that uses per default a lot of anti patterns. Those decision are 3/4 years old and meanwhile there were to less contribution to finish this monster project. Just release now a old architecture, full of smelly code and old patterns, just to release something does not make sense. However, there's no point in postpone such fundamental changes just because it would push the release some weeks backwards, also because we have still a lot of bugs to fix where the contribution is at the moment to less. It appears I'm the only person that understand Propel's architecture completely till the closest corner and contributing fixes to complicated issues. If this would stop Propel 2 is dead.

Also, your branch isn't testable

Please stop complaining. It's a WIP, nobody said it is workable.

Member

marcj commented Oct 29, 2014

I don't understand the difference between the Query and the Repository classes. Getting rid of Peer classes was the one big benefit of Propel2, I don't think you need to generate more than 2 classes per entity.

I haven't yet fully defined the use case of repository, but it should act as middle man. Query classes are only there to fire custom queries directly at the underlying database, bypassing unitofwork and all events (if you use ->update or ->delete)

I see that objects still have a save() method. How do they get the UnitOfWork instance?

See

At wish a active-record trait is injected or can be used to provide active-record methods like save(), delete() etc

It uses the global configuration, as currently in Propel 2.

Could you show examples of generated Entity/ActiveRecord/Repository code? It's hard to tell if you're heading in the right direction otherwise.

"right direction" defined by whom?

The code of the PR is too large to get even a slightest look. Your commit messages are meaningless. This make reviewing impossible, and basically means that this will be a one man project. I'm strongly worried by this.

Indeed, they are meaningless. They weren't meant to have meaning just for me as backup commits. I've rebased it now. Btw, it's already almost a one man project.

Many of the people who use Propel actually don't like Doctrine and EM, for many reasons (verbosity, magic, need to carry the em everywhere, proxies, DQL, POPO). This major change will probably make Propel lose them. Do you have an idea of how many would stay?

I really know the benefits of Propel over Doctrine, that's the reason why it's almost compatible. As you see the schema definition became even easier for relations. If you use optional active-record then it behaves almost the same like at the moment, so you don't need to know anything about "em".

I'm surprised to see that PR at a time where Propel 2.0 is almost ready. This will delay the release of the 2.0 a great deal, and to me, this means the death of Propel (not enough progress in stable releases). I advise you to finish Propel 2.0 first, using the architecture that was decided before (i.e. do not change the AR and AQ API, just get rid of Peer classes), then work on this new architecture for Propel 3.0.

I won't develop on a library that uses per default a lot of anti patterns. Those decision are 3/4 years old and meanwhile there were to less contribution to finish this monster project. Just release now a old architecture, full of smelly code and old patterns, just to release something does not make sense. However, there's no point in postpone such fundamental changes just because it would push the release some weeks backwards, also because we have still a lot of bugs to fix where the contribution is at the moment to less. It appears I'm the only person that understand Propel's architecture completely till the closest corner and contributing fixes to complicated issues. If this would stop Propel 2 is dead.

Also, your branch isn't testable

Please stop complaining. It's a WIP, nobody said it is workable.

@marcj

This comment has been minimized.

Show comment
Hide comment
@marcj

marcj Oct 29, 2014

Member

This fixes those issues:

#261
#234
#182
#144
#42
#361
#356
#667
#636
#523

Member

marcj commented Oct 29, 2014

This fixes those issues:

#261
#234
#182
#144
#42
#361
#356
#667
#636
#523

@mpscholten

View changes

Show outdated Hide outdated src/Propel/Generator/Builder/Om/Component/BuildComponent.php
@marcj

This comment has been minimized.

Show comment
Hide comment
@marcj

marcj Oct 29, 2014

Member

Btw, no need to review the code yet in detail. Will be changed much. Would rather talk about the whole concept and architecture, so we use the terms under the right definition.

Member

marcj commented Oct 29, 2014

Btw, no need to review the code yet in detail. Will be changed much. Would rather talk about the whole concept and architecture, so we use the terms under the right definition.

@ClementGautier

This comment has been minimized.

Show comment
Hide comment
@ClementGautier

ClementGautier Oct 29, 2014

I won't develop on a library that uses per default a lot of anti patterns. Those decision are 3/4 years ago and meanwhile there were to less contribution to finish this monster project. Just release now a old architecture, full of smelly code and old patterns, just to release something does not make sense. However, there's no point in postpone such fundamental changes just because it would pushes the release some weeks backwards, also because we have still a lot of bugs to fix where the contribution is at the moment to less. It appears I'm the only person that understand Propel's architecture completely till the closest corner and contributing fixes to complicated issues. If this would stop Propel 2 is dead.

=> +1 Lets be realistic: noone uses Propel >= 2.* for production purpose actually. Releasing a "stable" version of code implies that someone will have to guarantee a long time support or at least an active support. And nobody want to support smelly code and old patterns.

ClementGautier commented Oct 29, 2014

I won't develop on a library that uses per default a lot of anti patterns. Those decision are 3/4 years ago and meanwhile there were to less contribution to finish this monster project. Just release now a old architecture, full of smelly code and old patterns, just to release something does not make sense. However, there's no point in postpone such fundamental changes just because it would pushes the release some weeks backwards, also because we have still a lot of bugs to fix where the contribution is at the moment to less. It appears I'm the only person that understand Propel's architecture completely till the closest corner and contributing fixes to complicated issues. If this would stop Propel 2 is dead.

=> +1 Lets be realistic: noone uses Propel >= 2.* for production purpose actually. Releasing a "stable" version of code implies that someone will have to guarantee a long time support or at least an active support. And nobody want to support smelly code and old patterns.

@mpscholten

This comment has been minimized.

Show comment
Hide comment
@mpscholten

mpscholten Oct 29, 2014

Member

I really like this refactoring. A very modern approach to our problems.

But I'm worried about the long delay until we can go stable. From a developer perspective this is really great, but from the perspective of a propel user this doesn't make happy.

Member

mpscholten commented Oct 29, 2014

I really like this refactoring. A very modern approach to our problems.

But I'm worried about the long delay until we can go stable. From a developer perspective this is really great, but from the perspective of a propel user this doesn't make happy.

@fzaninotto

This comment has been minimized.

Show comment
Hide comment
@fzaninotto

fzaninotto Oct 29, 2014

Member

Let me rephrase what I wrote: "right direction" is wrong. I should have written "a direction I, as a user, would understand and support".

So I don't understand this direction, but you're the leader, so do whatever you want.

As a former core developer, it makes me sad.

Member

fzaninotto commented Oct 29, 2014

Let me rephrase what I wrote: "right direction" is wrong. I should have written "a direction I, as a user, would understand and support".

So I don't understand this direction, but you're the leader, so do whatever you want.

As a former core developer, it makes me sad.

@marcj

This comment has been minimized.

Show comment
Hide comment
@marcj

marcj Oct 29, 2014

Member

As a former core developer, it makes me sad.

Sorry, I don't wanted to make you feel sad. What exactly don't you like? Maybe it's just not correctly described, because I guess we have really the same thoughts about Propel and its benefits.

Member

marcj commented Oct 29, 2014

As a former core developer, it makes me sad.

Sorry, I don't wanted to make you feel sad. What exactly don't you like? Maybe it's just not correctly described, because I guess we have really the same thoughts about Propel and its benefits.

@lunika

This comment has been minimized.

Show comment
Hide comment
@lunika

lunika Oct 29, 2014

Contributor

I agree @fzaninotto and @tayhimself, people I know use Propel because they don't like EM and it's really different than doctrine and I think they were waiting for a stable version 2 with all the already known features

@ClementGautier : unfortunately projects are using Propel 2 and are stuck on a specific version because many BC where introduce between alpha 2 and 3.

BTW using an alpha version was a known risk (and now I know, a really bad idea) so I can't complain about this modification but after many years of development I wasn't thinking it's possible to introduce so many changes.

I think most of Behaviour have to be rewrite with this modification, am I wrong ?

Contributor

lunika commented Oct 29, 2014

I agree @fzaninotto and @tayhimself, people I know use Propel because they don't like EM and it's really different than doctrine and I think they were waiting for a stable version 2 with all the already known features

@ClementGautier : unfortunately projects are using Propel 2 and are stuck on a specific version because many BC where introduce between alpha 2 and 3.

BTW using an alpha version was a known risk (and now I know, a really bad idea) so I can't complain about this modification but after many years of development I wasn't thinking it's possible to introduce so many changes.

I think most of Behaviour have to be rewrite with this modification, am I wrong ?

@marcj

This comment has been minimized.

Show comment
Hide comment
@marcj

marcj Oct 29, 2014

Member

Just to be clear: The whole $session (in Propel) and EntityManager stuff (from doctrine) is completely optional in Propel2, because you can still have active-record entities. This means: You don't have to use $em or something, you can still use $entity->save().

Member

marcj commented Oct 29, 2014

Just to be clear: The whole $session (in Propel) and EntityManager stuff (from doctrine) is completely optional in Propel2, because you can still have active-record entities. This means: You don't have to use $em or something, you can still use $entity->save().

@fzaninotto

This comment has been minimized.

Show comment
Hide comment
@fzaninotto

fzaninotto Oct 29, 2014

Member

What makes me sad is that you're dismissing a remark for the only person who checked out your code and tried running it. What makes me sad is that you don't see the benefit of delivering vs having something clean. What makes me sad is that you took over a project, then call it "full of anti-patterns" and pivot radically without notice. What makes me sad is that current Propel users have been waiting for Propel2 for a long time, and it will never come out as it was advertised.

But once again, seeing the time you spend on this project, you totally have the right to make it what you want and not what the users want. And if this is a Doctrine clone, so be it.

Member

fzaninotto commented Oct 29, 2014

What makes me sad is that you're dismissing a remark for the only person who checked out your code and tried running it. What makes me sad is that you don't see the benefit of delivering vs having something clean. What makes me sad is that you took over a project, then call it "full of anti-patterns" and pivot radically without notice. What makes me sad is that current Propel users have been waiting for Propel2 for a long time, and it will never come out as it was advertised.

But once again, seeing the time you spend on this project, you totally have the right to make it what you want and not what the users want. And if this is a Doctrine clone, so be it.

@marcj

This comment has been minimized.

Show comment
Hide comment
@marcj

marcj Oct 30, 2014

Member

What makes me sad is that you're dismissing a remark for the only person who checked out your code and tried running it.

I don't dismiss your response. I responded to each point you made.

What makes me sad is that you don't see the benefit of delivering vs having something clean.

We have neither of it. Builder classes are currently extremely unmaintainable (ObjectBuilder.php 6000+ lines of code, QuerBuilder 1900, TableMap 1400), which means is not clean at all and a extremely pain to fix there bugs. And we can not even deliver it because it would be immediately dead after release because we'd work on Propel 3 right after the v2 release. I'd just make no sense if we want to follow modern architectures and design patterns.

What makes me sad is that you took over a project, then call it "full of anti-patterns" and pivot radically without notice.

So, when one takes over a project closing eyes from flaws is the way to go? I'm sure you know also the flaws of Propel and saying it loud shouldn't make you sad. It's just the truth.
I don't change the project radically for the end user. The api for dealing with query classes and entity classes is still the same. You have just additionally to the old active-record pattern now also the way to do it more modern that gives you some benefits.
Btw, I didn't say "full of anti-patterns", but "lot of anti patterns", which is just plain true. See all those unnecessary static methods, the hack with loading TableMap during class loading, the not being able to unit test models without mocking dozens of classes or resetting global static variables. Just to name some few.

What makes me sad is that current Propel users have been waiting for Propel2 for a long time, and it will never come out as it was advertised.

That makes me sad as well. This wasn't my fault. Some years ago it was introduced to allow POPO, which is not the case right now before this PR. It never would have been released the way it was advertised, even before this PR.

right to make it what you want and not what the users want.

Sorry, what are you talking? Don't get me wrong, I highly respect you and your work, but I can't believe you said this. You know what all users want? They don't want better code base, faster performance, more decoupled classes with more clear separation of concerns and better testability of their models? I highly doubt that. I agree, Propel users want active record - and they can still use active record the way as before even with this PR. So I don't see the point what this PR brings users don't want to have. Maybe you can explain in more detail?

And if this is a Doctrine clone, so be it.

Propel 2, even after this PR, is completely different to Doctrine. Using successful and widely adopted patterns like unitOfWork under the hood doesn't mean Propel 2 will be a Doctrine clone. It's far far away from this plain wrong statement.

Member

marcj commented Oct 30, 2014

What makes me sad is that you're dismissing a remark for the only person who checked out your code and tried running it.

I don't dismiss your response. I responded to each point you made.

What makes me sad is that you don't see the benefit of delivering vs having something clean.

We have neither of it. Builder classes are currently extremely unmaintainable (ObjectBuilder.php 6000+ lines of code, QuerBuilder 1900, TableMap 1400), which means is not clean at all and a extremely pain to fix there bugs. And we can not even deliver it because it would be immediately dead after release because we'd work on Propel 3 right after the v2 release. I'd just make no sense if we want to follow modern architectures and design patterns.

What makes me sad is that you took over a project, then call it "full of anti-patterns" and pivot radically without notice.

So, when one takes over a project closing eyes from flaws is the way to go? I'm sure you know also the flaws of Propel and saying it loud shouldn't make you sad. It's just the truth.
I don't change the project radically for the end user. The api for dealing with query classes and entity classes is still the same. You have just additionally to the old active-record pattern now also the way to do it more modern that gives you some benefits.
Btw, I didn't say "full of anti-patterns", but "lot of anti patterns", which is just plain true. See all those unnecessary static methods, the hack with loading TableMap during class loading, the not being able to unit test models without mocking dozens of classes or resetting global static variables. Just to name some few.

What makes me sad is that current Propel users have been waiting for Propel2 for a long time, and it will never come out as it was advertised.

That makes me sad as well. This wasn't my fault. Some years ago it was introduced to allow POPO, which is not the case right now before this PR. It never would have been released the way it was advertised, even before this PR.

right to make it what you want and not what the users want.

Sorry, what are you talking? Don't get me wrong, I highly respect you and your work, but I can't believe you said this. You know what all users want? They don't want better code base, faster performance, more decoupled classes with more clear separation of concerns and better testability of their models? I highly doubt that. I agree, Propel users want active record - and they can still use active record the way as before even with this PR. So I don't see the point what this PR brings users don't want to have. Maybe you can explain in more detail?

And if this is a Doctrine clone, so be it.

Propel 2, even after this PR, is completely different to Doctrine. Using successful and widely adopted patterns like unitOfWork under the hood doesn't mean Propel 2 will be a Doctrine clone. It's far far away from this plain wrong statement.

@cristianoc72

This comment has been minimized.

Show comment
Hide comment
@cristianoc72

cristianoc72 Oct 30, 2014

Member

@marcj if you think I could help, you just holler. Some easy and boring stuff....
By now, I'm just studying those patterns: I haven't enough technical skills to completely undestand your work.

Anyway, as Propel user, what I really matter is:

  • use Active Record and Active Query in the (almost) same way, which is the reason why I prefer Propel to Doctrine
  • performance benefits, thanks to generation
  • leave my old schema.xml files as is, as much as possible or, at least, the possibility to use a command or a script to automatically update them.
  • release a stable 2.0 version before my old age (it's not so far: I'm 42 😄 )
Member

cristianoc72 commented Oct 30, 2014

@marcj if you think I could help, you just holler. Some easy and boring stuff....
By now, I'm just studying those patterns: I haven't enough technical skills to completely undestand your work.

Anyway, as Propel user, what I really matter is:

  • use Active Record and Active Query in the (almost) same way, which is the reason why I prefer Propel to Doctrine
  • performance benefits, thanks to generation
  • leave my old schema.xml files as is, as much as possible or, at least, the possibility to use a command or a script to automatically update them.
  • release a stable 2.0 version before my old age (it's not so far: I'm 42 😄 )
@guilhermeaiolfi

This comment has been minimized.

Show comment
Hide comment
@guilhermeaiolfi

guilhermeaiolfi Oct 30, 2014

So, I was waiting for Propel 2.0 but I couldn't wait so I went with Doctrine. Maybe, for fans of Active Record, I think what @marcj said is true: in a data-mapper you have a clear separation of concerns and I think it's great to have it in propel. I also think you all are not being fair with @marcj b/c since he said that the current, and more stable, way of use propel will be kept I don't see any problem in he trying new things. Even if the old one is not going to be supported by him.

If it wasn't for him, there wouldn't be even a possibility of a 2.0 release. So, be nice. That being said, this PR is something that could bring me back to Propel. +1 from me.

guilhermeaiolfi commented Oct 30, 2014

So, I was waiting for Propel 2.0 but I couldn't wait so I went with Doctrine. Maybe, for fans of Active Record, I think what @marcj said is true: in a data-mapper you have a clear separation of concerns and I think it's great to have it in propel. I also think you all are not being fair with @marcj b/c since he said that the current, and more stable, way of use propel will be kept I don't see any problem in he trying new things. Even if the old one is not going to be supported by him.

If it wasn't for him, there wouldn't be even a possibility of a 2.0 release. So, be nice. That being said, this PR is something that could bring me back to Propel. +1 from me.

@ClementGautier

This comment has been minimized.

Show comment
Hide comment
@ClementGautier

ClementGautier Oct 31, 2014

@marcj I would like to propose a PSR about UnitOfWork and DataMapper to @php-fig . Do you think that we can find a common interface between Doctrine2 and Propel2 ?

ClementGautier commented Oct 31, 2014

@marcj I would like to propose a PSR about UnitOfWork and DataMapper to @php-fig . Do you think that we can find a common interface between Doctrine2 and Propel2 ?

@hhamon

This comment has been minimized.

Show comment
Hide comment
@hhamon

hhamon Oct 31, 2014

Member

What's the point? It's like proposing the DIC PSR. It makes no sense as it's very specific to a particular framework/library IMO.

Member

hhamon commented Oct 31, 2014

What's the point? It's like proposing the DIC PSR. It makes no sense as it's very specific to a particular framework/library IMO.

@ClementGautier

This comment has been minimized.

Show comment
Hide comment
@ClementGautier

ClementGautier Oct 31, 2014

@hhamon Not really. UOW and DataMapper have more a complex interface than a get method. It would allow third party library to relly on this Interface instead of the ORM interface. It would be a big step for ORM interoperability.

ClementGautier commented Oct 31, 2014

@hhamon Not really. UOW and DataMapper have more a complex interface than a get method. It would allow third party library to relly on this Interface instead of the ORM interface. It would be a big step for ORM interoperability.

@hhamon

This comment has been minimized.

Show comment
Hide comment
@hhamon

hhamon Oct 31, 2014

Member

Does it really make sens to make ORM interoperable? Are you really dealing with multiple ORM on the same project in real life?

Member

hhamon commented Oct 31, 2014

Does it really make sens to make ORM interoperable? Are you really dealing with multiple ORM on the same project in real life?

@staabm

This comment has been minimized.

Show comment
Hide comment
@staabm

staabm Oct 31, 2014

Member

this disussion should not take place in this issue. please open another one or maybe even use another channel rathen then discussing on an issue tracker.

Member

staabm commented Oct 31, 2014

this disussion should not take place in this issue. please open another one or maybe even use another channel rathen then discussing on an issue tracker.

@marcj

This comment has been minimized.

Show comment
Hide comment
@marcj

marcj Oct 31, 2014

Member

Do you think that we can find a common interface between Doctrine2 and Propel2 ?

No.

It would be a big step for ORM interoperability.

Indeed. A ORM interoperability nobody needs.

Member

marcj commented Oct 31, 2014

Do you think that we can find a common interface between Doctrine2 and Propel2 ?

No.

It would be a big step for ORM interoperability.

Indeed. A ORM interoperability nobody needs.

@mkusher

This comment has been minimized.

Show comment
Hide comment
@mkusher

mkusher Jul 8, 2015

$carRepository = $configuration->getRepository(‘\Car’); //provided usually per services/DI.

$car = $carRepository->find(23);

$brand = new Brand(‘Ford’);
$car->setBrand($brand);

$session->persist($brand);
$session->persist($car);
$session->commit();
//or
$car->save(); //cascade save as usual.

why should we call Session::persist on $car? Shouldn't it be already in session object after find?

mkusher commented Jul 8, 2015

$carRepository = $configuration->getRepository(‘\Car’); //provided usually per services/DI.

$car = $carRepository->find(23);

$brand = new Brand(‘Ford’);
$car->setBrand($brand);

$session->persist($brand);
$session->persist($car);
$session->commit();
//or
$car->save(); //cascade save as usual.

why should we call Session::persist on $car? Shouldn't it be already in session object after find?

@motin

This comment has been minimized.

Show comment
Hide comment
@motin

motin Sep 27, 2015

Contributor

The latest state of Propel2, written 2015-06-27: http://propelorm.org/blog/2015/06/27/propel2-current-state-and-future.html

Contributor

motin commented Sep 27, 2015

The latest state of Propel2, written 2015-06-27: http://propelorm.org/blog/2015/06/27/propel2-current-state-and-future.html

@harikt

This comment has been minimized.

Show comment
Hide comment
@harikt

harikt Sep 28, 2015

Contributor

Thank you @motin for the link. Thanks @marcj for the blog post.

Contributor

harikt commented Sep 28, 2015

Thank you @motin for the link. Thanks @marcj for the blog post.

@marcj

This comment has been minimized.

Show comment
Hide comment
@marcj

marcj Oct 2, 2015

Member

why should we call Session::persist on $car? Shouldn't it be already in session object after find?

Well, you're obviously right :)

Member

marcj commented Oct 2, 2015

why should we call Session::persist on $car? Shouldn't it be already in session object after find?

Well, you're obviously right :)

@motin

This comment has been minimized.

Show comment
Hide comment
@motin

motin Dec 1, 2015

Contributor

From the blog post from 2015-06-27:

I'm planing now to write every ~two weeks a blog post about what has been done in that data-mapper development, so you're up to date.

Any chance of a 6 month update this month instead?
Thanks again for Propel, it is the best PHP ORM I've ever used :)

Contributor

motin commented Dec 1, 2015

From the blog post from 2015-06-27:

I'm planing now to write every ~two weeks a blog post about what has been done in that data-mapper development, so you're up to date.

Any chance of a 6 month update this month instead?
Thanks again for Propel, it is the best PHP ORM I've ever used :)

@marcj

This comment has been minimized.

Show comment
Hide comment
@marcj

marcj Dec 1, 2015

Member

Not yet, pretty busy and wild times in my personal life. Not much time for open-source at the moment.

Member

marcj commented Dec 1, 2015

Not yet, pretty busy and wild times in my personal life. Not much time for open-source at the moment.

@mpscholten

This comment has been minimized.

Show comment
Hide comment
@mpscholten

mpscholten Dec 6, 2015

Member

Is there a way we can help moving this pr forward? Maybe we can split the remaining tasks into several smaller issues and then distribute the work :)

Member

mpscholten commented Dec 6, 2015

Is there a way we can help moving this pr forward? Maybe we can split the remaining tasks into several smaller issues and then distribute the work :)

@marcj

This comment has been minimized.

Show comment
Hide comment
@marcj

marcj Dec 6, 2015

Member

Mh yeah, let me upload my current version. I'm going to create then a new branch here and create some issues to distribute the work. @cristianoc72 was working on something too iirc.

Member

marcj commented Dec 6, 2015

Mh yeah, let me upload my current version. I'm going to create then a new branch here and create some issues to distribute the work. @cristianoc72 was working on something too iirc.

@marcj marcj closed this Dec 6, 2015

@marcj

This comment has been minimized.

Show comment
Hide comment
@marcj

marcj Dec 6, 2015

Member

Branch data-mapper has been created to play with it or continue easier development across the team. Test-suite is 10% green. Now we need to make some sub-tasks based on that. :)

Member

marcj commented Dec 6, 2015

Branch data-mapper has been created to play with it or continue easier development across the team. Test-suite is 10% green. Now we need to make some sub-tasks based on that. :)

@mpscholten

This comment has been minimized.

Show comment
Hide comment
@mpscholten

mpscholten Dec 6, 2015

Member

👍 thanks. I'll take a look over it :)

Member

mpscholten commented Dec 6, 2015

👍 thanks. I'll take a look over it :)

@cristianoc72

This comment has been minimized.

Show comment
Hide comment
@cristianoc72

cristianoc72 Dec 6, 2015

Member

Sure! I've ported I18nBehavior and I'm working on one-to-many relation. I'm
fixing the tests about it. I confess it makes me crazy :-)
Il 06/dic/2015 18:00, "Marc J. Schmidt" notifications@github.com ha
scritto:

Mh yeah, let me upload my current version. I'm going to create then a new
branch here and create some issues to distribute the work. @cristianoc72
https://github.com/cristianoc72 was working on something too iirc.


Reply to this email directly or view it on GitHub
#795 (comment).

Member

cristianoc72 commented Dec 6, 2015

Sure! I've ported I18nBehavior and I'm working on one-to-many relation. I'm
fixing the tests about it. I confess it makes me crazy :-)
Il 06/dic/2015 18:00, "Marc J. Schmidt" notifications@github.com ha
scritto:

Mh yeah, let me upload my current version. I'm going to create then a new
branch here and create some issues to distribute the work. @cristianoc72
https://github.com/cristianoc72 was working on something too iirc.


Reply to this email directly or view it on GitHub
#795 (comment).

@marcj

This comment has been minimized.

Show comment
Hide comment
@marcj

marcj Dec 7, 2015

Member

I confess it makes me crazy :-)

Feel free to write me in Skype if you got into trouble 8-)

Member

marcj commented Dec 7, 2015

I confess it makes me crazy :-)

Feel free to write me in Skype if you got into trouble 8-)

@gossi

This comment has been minimized.

Show comment
Hide comment
@gossi

gossi Dec 8, 2015

Contributor

Nice to see this going forward, thanks guy :)

Contributor

gossi commented Dec 8, 2015

Nice to see this going forward, thanks guy :)

@vendethiel

This comment has been minimized.

Show comment
Hide comment
@vendethiel

vendethiel Feb 11, 2016

@marcj you might want to update the wiki

vendethiel commented Feb 11, 2016

@marcj you might want to update the wiki

@roquie

This comment has been minimized.

Show comment
Hide comment
@roquie

roquie Mar 8, 2016

@marcj when release date (odm)? I can't wait to see that. :)

roquie commented Mar 8, 2016

@marcj when release date (odm)? I can't wait to see that. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment