We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!

ORM

    • 28042 ☆ A M B ☆
    • 24,524 Posts
    http://www.phpobjectgenerator.com/

    I seem to remember something about this general subject before, but couldn’t find any reference to it. From what I’ve seen, it looks very interesting. For example, I have queries like this in DocMan:

    "SELECT fd.*, wua.fullname, fc.catname FROM $dbase.files_data fd
        LEFT JOIN ".$modx->getFullTableName('web_user_attributes')." wua ON fd.owner = wua.id
        LEFT JOIN $dbase.files_categories fc ON fd.category = fc.id
        LEFT JOIN $dbase.files_perms fp ON fd.id = fp.fid 
        WHERE fp.uid = '$uid' AND fp.rights = '1' AND fd.category ".$catid." 
        ORDER BY fd.realname";


    It wasn’t easy and it certainly wasn’t fun, and I still don’t feel confident about it. Something like this POG would make the whole business a lot easier, as well as enforcing strict OO design. And it’s BSD licensed. And the site has tutorials on using it with Ajax.
      Studying MODX in the desert - http://sottwell.com
      Tips and Tricks from the MODX Forums and Slack Channels - http://modxcookbook.com
      Join the Slack Community - http://modx.org
      • 25663 MODX Staff
      • 12,272 Posts
      Jason is doing a lot of work with ORM patterns in his Tattoo demo that should start surfacing sometime soon (this month for sure).
        Ryan Thrash, MODX Co-Founder
        Follow me on Twitter at @rthrash or catch my occasional unofficial thoughts at thrash.me
        • 28042 ☆ A M B ☆
        • 24,524 Posts
        It does look like for really good ORM stuff you need PHP 5. Digging into this, I see it won’t save me from having to work out my own joins for complex queries. <sigh> But it’s still a pretty nice tool for more basic queries. I see where the basis for the MODx DBAPI came from.
          Studying MODX in the desert - http://sottwell.com
          Tips and Tricks from the MODX Forums and Slack Channels - http://modxcookbook.com
          Join the Slack Community - http://modx.org
          • 22303 MODX Staff
          • 10,725 Posts
          Quote from: rthrash at Feb 12, 2006, 04:52 PM

          Jason is doing a lot of work with ORM patterns in his Tattoo demo that should start surfacing sometime soon (this month for sure).
          Correct; I just finished my second major commit on the Tattoo line of development (if you have SVN access, you can check it out in my branch), and should have some significant announcements either this week or next, once I get some basic manager pages worked out, and get a few snippets converted.

          A little history; after reviewing POG and a host of other ORM tools/frameworks for PHP, I chose something called Propel (http://propel.phpdb.org/).  This selection was based on Propel’s extensive feature list and a 2-week proof of concept project I completed around Christmas time (in which I implemented the current MODx data layer and code using Propel).  Though some of the other frameworks provided similar functionality to Propel, the overall maturity of the Propel architecture drew me in.  It’s based on a similar open-source project from the Apache project, called Torque (http://db.apache.org/torque), implemented in Java, and is supplemented by several other very useful projects, which I am also making extensive use of in developing Tattoo.

          These supporting projects include an impressive build-framework called Phing, based on Apache Ant, a very popular XML-based build tool for Java (both Ant and Phing build files integrate deeply into Eclipse).  Propel uses Phing to organize and control the class generation facilities, and will allow us to easily build automated nightly builds and accomplish other complex development automation with very little effort.  For instance, I can describe a new table column we might want to add to one or more tables/objects in our data model using Propel’s XML schema, open the project’s /_model/build.xml file in Eclipse, right click on the Propel Build task and select Run as Ant Task; no more than five seconds later, all of the base classes for the object model are regenerated with the new getters/setters for the new attribute/column, and are ready to use in the Tattoo API.  Very slick stuff.

          The DB access layer in Propel is based on yet another open source project, called Creole.  Creole offers support for 5 major RDBMS currently (including PostgreSQL, Oracle and MS SQL Server), and 2 different data access models: the core model based on Java’s JDBC API and another called Jargon, based on the traditional ASP-like RecordSet API.  In my current code, this gives you three different ways to interact with the data, as I reimplemented the DBAPI to utilize Creole conventions with little or no change to the public API methods.  So take your pick on directly accessing the data layer, if you must.  ;-)

          Quote from: sottwell at Feb 12, 2006, 05:42 PM

          It does look like for really good ORM stuff you need PHP 5.  Digging into this, I see it won’t save me from having to work out my own joins for complex queries.  <sigh>  But it’s still a pretty nice tool for more basic queries.  I see where the basis for the MODx DBAPI came from.

          Agreed; I originally was going to produce Tattoo with a PHP5 and PHP4 run-time, but the advanced OO features of PHP5, especially Reflection and Exception handling, are IMO essential to producing a truly useful OO version of MODx.  So I do think it’s best to leave PHP4 to the still evolving MODx codebase while we explore the potential of PHP5 with Tattoo.

          And speaking of complex joins, one of the best features of Propel is the auto-generation of joins to tables related by foreign-key constraints in the Propel schema.  For instance, consider this simple way of retrieving all the Elements related to the current Element by a column called `parent_guid`:
          $crit= new Criteria();
          $crit->add(ElementPeer :: getColumnName(ElementPeer :: PARENT_GUID), null, Criteria :: ISNOTNULL);
          if ($this->getElementsRelatedByParentGuid($crit)) {
          ...

          NOTE: Elements will replace all current MODx "resource" components, from Templates to Chunks to Snippets to Plugins, plus a whole lot more, as you will see in the upcoming days

          Or consider retrieving every Resource object in the database, and preloading all related objects by foreign keys, using a single query (which would be full of LEFT JOIN statements, like your original example Susan):
          $criteria= new Criteria();
          $critContextKey= $criteria->getNewCriterion(ResourcePeer :: getColumnName(ResourcePeer :: CONTEXT_KEY), $obj->getKey());
          $critContextKey->addOr($criteria->getNewCriterion(ResourcePeer :: getColumnName(ResourcePeer :: CONTEXT_KEY), NULL, Criteria :: ISNULL));
          $criteria->add($critContextKey);
          $collResources= $cms->getCollection('tattoo.Resource', $criteria, 'doSelectJoinAll');

          NOTE: Resource in Tattoo is the name for any web resource that can be accessed via URL (replaces site_content or documents and weblinks from MODx)

          Now, a couple of things in this example may seem like they are a little-bit on the side of overkill, such as the getColumnName method required to get the actual physical table column name, but this was necessary to ensure that the table name with the appropriate table_prefix is added to the column name when working with complex joins.  Overall however, with a little OO experience, this approach is the only way to make your objects and code truly portable across disparate DB platforms, and IMO, is much simpler than trying to figure out which table names and columns to include in a string of SQL code.

          I welcome any comments or feedback on ORM in general, or the Tattoo/Propel work in progress.  More soon...
            • 32241
            • 1,495 Posts
            As for me, it sounds really complicated. I mean a few lines of the code can be replaced with a simple column name and sql statement. But I do understand the portability accross multiple DB platform which need to be achieved by using this kind of method. I don’t know any other good method to do this, so I will assume that this is the best way to go.

            So, I’m looking forward to hear the major news for Tattoo.
              Wendy Novianto
              [font=Verdana]PT DJAMOER Technology Media
              [font=Verdana]Xituz Media
              • 28042 ☆ A M B ☆
              • 24,524 Posts
              I moved on from POG to the PEAR DB_DataObject library, and like it very very much. If only it weren’t so tied up with that wretched PEAR system. The biggest advantage I can see so far is that it does support PHP 4. Most of the cheap web hosting servers are running variations of PHP 4 and probably won’t be upgrading any time soon. I would really like to rewrite the DocMan document management snippet/application, "refactoring" it into nice neat objects and using something like DB_DataObject for the storage.
                Studying MODX in the desert - http://sottwell.com
                Tips and Tricks from the MODX Forums and Slack Channels - http://modxcookbook.com
                Join the Slack Community - http://modx.org
                • 22303 MODX Staff
                • 10,725 Posts
                Quote from: Djamoer at Feb 13, 2006, 03:29 PM

                As for me, it sounds really complicated. I mean a few lines of the code can be replaced with a simple column name and sql statement.

                It’s really not complicated at all and here is the SQL statement you’d have to create to replace those lines of code you are talking about (see second example in original post)...
                SELECT resource.ID, resource.CLASS_KEY, resource.CONTEXT_KEY, resource.ALIAS, resource.PUBLISHED, resource.PUBLISH_DATE, resource.UNPUBLISH_DATE, resource.PARENT_ID, resource.IS_FOLDER, resource.RICH_TEXT, resource.BASE_ELEMENT_ID, resource.SORT_INDEX, resource.SEARCHABLE, resource.CACHEABLE, resource.CREATED_BY, resource.CREATED_ON, resource.EDITED_BY, resource.EDITED_ON, resource.DELETED, resource.DONT_HIT, resource.HAS_KEYWORDS, resource.HAS_METATAGS, resource.PRIVATE_WEB, resource.PRIVATE_MGR, resource.CONTENT_DISPOSITION, resource.HIDE_MENU, context.KEY, context.DESCRIPTION, element.ID, element.CLASS_KEY, element.CONTEXT_KEY, element.NAME, element.DESCRIPTION, element.EDITOR_TYPE, element.CATEGORY_ID, element.LOCKED, element.PROPERTIES, element.STOP_PROPAGATION, element.INHERIT, element.DISABLED, element.GUID, element.PARENT_GUID, element.WRAP, element.ICON, element.INPUT_CLASS, element.INPUT_PARAMS, element.TRANSFORM_CLASS, element.TRANSFORM_PARAMS, element.CONTENT_ID, element.SORT_INDEX, element.CACHEABLE, user.ID, user.USERNAME, user.PASSWORD, user.CACHE_PASSWORD, user.IS_REMOTE, user.USER_PROFILE_ID, user.ID, user.USERNAME, user.PASSWORD, user.CACHE_PASSWORD, user.IS_REMOTE, user.USER_PROFILE_ID FROM resource, context, element, user WHERE (resource.CONTEXT_KEY=? OR resource.CONTEXT_KEY IS NULL ) AND resource.CONTEXT_KEY=context.KEY AND resource.BASE_ELEMENT_ID=element.ID AND resource.CREATED_BY=user.ID AND resource.EDITED_BY=user.ID


                This hides an enormous amount of relational DB complexity from the developer, making it much easier to complete the job at hand. And, in this example, the use of the doSelectAll method creates all of the Resource objects, and relates all of the objects associated by foreign key constraints to each Resource, automatically. So after executing this, you could get all of the related data from any related table on any Resource without another query required.
                  • 32241
                  • 1,495 Posts
                  Thanks for straighten it up Jason. It’s true, and in fact it’s a lot easier to read, after we understand the syntax. Like I said, I can’t be more agree than this.

                  Thanks for sharing Jason.
                    Wendy Novianto
                    [font=Verdana]PT DJAMOER Technology Media
                    [font=Verdana]Xituz Media