Changeset 3107

Show
Ignore:
Timestamp:
04/13/08 08:06:52 (3 months ago)
Author:
pmjones
Message:

Solar_Sql_Model_Related, _Belongs_To, _Has_Many, and _Has_One


Added more "self-knowledge" to relation objects so they can take over the
heavy-lifting current handled inside the model object.

* [ADD] Method modSelectCountPages() to modify the count-pages SELECT from a

native model. This helps to make sure that eager-joins are honored when
counting pages.

* [ADD] Abstract method modSelectEager() to modify the fetch*() SELECT from a

native model. This pulls the logic for eager-joins out of the model object
and puts it in the relation object.

* [ADD] Support method _modSelectEager() to handle most types of eager joins,

with (has-one/belongs-to) or without (has-many) columns.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/Solar/Sql/Model/Related.php

    r2953 r3107  
    382382    /** 
    383383     *  
    384      * Creates a new selection object for records on this relationship
     384     * Creates a new selection object for fetching records from this relation
    385385     *  
    386386     * @param mixed $spec If an array, treated as params for a select  
     
    443443        // done 
    444444        return $select; 
     445    } 
     446     
     447    /** 
     448     *  
     449     * Modifies the SELECT from a native model countPages() call to join 
     450     * with the foreign model (especially on eager fetches). 
     451     *  
     452     * @param Solar_Sql_Select $select The SELECT from the native model 
     453     * countPages() method. 
     454     *  
     455     * @return void The SELECT is modified in place. 
     456     *  
     457     */ 
     458    public function modSelectCountPages($select) 
     459    { 
     460        // primary-key join condition on foreign table 
     461        $cond = "{$this->native_alias}.{$this->native_col} = " 
     462              . "{$this->foreign_alias}.{$this->foreign_col}"; 
     463         
     464        // add the join, no columns. 
     465        $select->leftJoin( 
     466            "{$this->foreign_table} AS {$this->foreign_alias}", 
     467            $cond 
     468        ); 
     469         
     470        // inheritance for foreign model 
     471        if ($this->foreign_inherit_col) { 
     472            $select->where( 
     473                "{$this->foreign_alias}.{$this->foreign_inherit_col} = ?", 
     474                $this->foreign_inherit_val 
     475            ); 
     476        } 
     477         
     478        // added where conditions for the join 
     479        $select->multiWhere($this->where); 
    445480    } 
    446481     
     
    508543    /** 
    509544     *  
     545     * Support method for modSelectEager().  This implementation works for 
     546     * belongs_to and has_one (with columns) and has_many (without columns). 
     547     * The "has_many through" relation needs its own implementation. 
     548     *  
     549     * @param Solar_Sql_Select $select The SELECT to be modified. 
     550     *  
     551     * @param array $cols Any columns to add to the SELECT. 
     552     *  
     553     * @return void The SELECT is modified in place. 
     554     *  
     555     */ 
     556    protected function _modSelectEager($select, $cols = null) 
     557    { 
     558        // primary-key join condition on foreign table 
     559        $cond = "{$this->native_alias}.{$this->native_col} = " 
     560              . "{$this->foreign_alias}.{$this->foreign_col}"; 
     561         
     562        // add the join 
     563        $select->leftJoin( 
     564            "{$this->foreign_table} AS {$this->foreign_alias}", 
     565            $cond, 
     566            $cols 
     567        ); 
     568         
     569        // inheritance for foreign model 
     570        if ($this->foreign_inherit_col) { 
     571            $select->where( 
     572                "{$this->foreign_alias}.{$this->foreign_inherit_col} = ?", 
     573                $this->foreign_inherit_val 
     574            ); 
     575        } 
     576         
     577        // added where conditions for the join 
     578        $select->multiWhere($this->where); 
     579    } 
     580     
     581    /** 
     582     *  
    510583     * Sets the foreign model instance based on user-defined relationship 
    511584     * options. 
     
    689762    /** 
    690763     *  
     764     * When the native model is doing a select and an eager-join is requested 
     765     * for this relation, this method modifies the select to add the eager 
     766     * join. 
     767     *  
     768     * @param Solar_Sql_Select $select The SELECT to be modified. 
     769     *  
     770     * @return void The SELECT is modified in place. 
     771     *  
     772     */ 
     773    abstract public function modSelectEager($select); 
     774     
     775    /** 
     776     *  
    691777     * Sets the relationship type. 
    692778     *  
  • trunk/Solar/Sql/Model/Related/BelongsTo.php

    r2933 r3107  
    1717 */ 
    1818class Solar_Sql_Model_Related_BelongsTo extends Solar_Sql_Model_Related { 
     19     
     20    /** 
     21     *  
     22     * When the native model is doing a select and an eager-join is requested 
     23     * for this relation, this method modifies the select to add the eager 
     24     * join. 
     25     *  
     26     * Automatically adds the foreign columns to the select. 
     27     *  
     28     * @param Solar_Sql_Select $select The SELECT to be modified. 
     29     *  
     30     * @return void The SELECT is modified in place. 
     31     *  
     32     */ 
     33    public function modSelectEager($select) 
     34    { 
     35        // build column names as "name__col" so that we can extract the 
     36        // the related data later. 
     37        $cols = array(); 
     38        foreach ($this->cols as $col) { 
     39            $cols[] = "$col AS {$this->name}__$col"; 
     40        } 
     41         
     42        $this->_modSelectEager($select, $cols); 
     43    } 
    1944     
    2045    /** 
  • trunk/Solar/Sql/Model/Related/HasMany.php

    r2953 r3107  
    1818 */ 
    1919class Solar_Sql_Model_Related_HasMany extends Solar_Sql_Model_Related { 
     20     
     21    /** 
     22     *  
     23     * When the native model is doing a select and an eager-join is requested 
     24     * for this relation, this method modifies the select to add the eager 
     25     * join. 
     26     *  
     27     * **Does not** add the foreign columns to the select, because that would 
     28     * result in really large result tables. Note that we fetch rows from the 
     29     * has-many relation separately, so not adding columns here is OK. 
     30     *  
     31     * @param Solar_Sql_Select $select The SELECT to be modified. 
     32     *  
     33     * @return void The SELECT is modified in place. 
     34     *  
     35     */ 
     36    public function modSelectEager($select) 
     37    { 
     38        if (empty($this->through)) { 
     39            // less-complex "has many" relationship. 
     40            $this->_modSelectEager($select); 
     41             
     42            // make the rows distinct, so we only get one row regardless of 
     43            // the number of related rows (since we're not selecting cols). 
     44            $select->distinct(true); 
     45             
     46            // done! 
     47            return; 
     48        } 
     49         
     50        // more-complex "has many through" relationship. 
     51        // join the native table to the mapping table. 
     52        $join_table = "{$this->through_table} AS {$this->through_alias}"; 
     53        $join_where = "{$this->native_alias}.{$this->native_col} = " 
     54                    . "{$this->through_alias}.{$this->through_native_col}"; 
     55         
     56        $select->leftJoin($join_table, $join_where); 
     57         
     58        // join the mapping table to the foreign table. 
     59        $join_table = "{$this->foreign_table} AS {$this->foreign_alias}"; 
     60        $join_where = "{$this->through_alias}.{$this->through_foreign_col} = " 
     61                    . "{$this->foreign_alias}.{$this->foreign_col}"; 
     62         
     63        $select->leftJoin($join_table, $join_where); 
     64         
     65        // make the rows distinct, so we only get one row regardless of 
     66        // the number of related rows (since we're not selecting cols). 
     67        $select->distinct(true); 
     68         
     69        // honor foreign inheritance 
     70        if ($this->foreign_inherit_col) { 
     71            $select->where( 
     72                "{$this->foreign_alias}.{$this->foreign_inherit_col} = ?", 
     73                $this->foreign_inherit_val 
     74            ); 
     75        } 
     76    } 
     77     
     78    /** 
     79     *  
     80     * Modifies the SELECT from a native model countPages() call to join 
     81     * with the foreign model (especially on eager fetches). 
     82     *  
     83     * While a regular "has many" relation uses the standard parent method, 
     84     * a "has many through" relation requires this override. 
     85     *  
     86     * @param Solar_Sql_Select $select The SELECT from the native model 
     87     * countPages() method. 
     88     *  
     89     * @return void The SELECT is modified in place. 
     90     *  
     91     */ 
     92    public function modSelectCountPages($select) 
     93    { 
     94        if (empty($this->through)) { 
     95            // less-complex "has many" relationship. 
     96            return parent::modSelectCountPages($select); 
     97        } 
     98         
     99        // more-complex "has many through" relationship. 
     100        // join the native table to the mapping table. 
     101        $join_table = "{$this->through_table} AS {$this->through_alias}"; 
     102        $join_where = "{$this->native_alias}.{$this->native_col} = " 
     103                    . "{$this->through_alias}.{$this->through_native_col}"; 
     104         
     105        $select->leftJoin($join_table, $join_where); 
     106         
     107        // join the mapping table to the foreign table. 
     108        $join_table = "{$this->foreign_table} AS {$this->foreign_alias}"; 
     109        $join_where = "{$this->through_alias}.{$this->through_foreign_col} = " 
     110                    . "{$this->foreign_alias}.{$this->foreign_col}"; 
     111         
     112        $select->leftJoin($join_table, $join_where); 
     113         
     114        // honor foreign inheritance 
     115        if ($this->foreign_inherit_col) { 
     116            $select->where( 
     117                "{$this->foreign_alias}.{$this->foreign_inherit_col} = ?", 
     118                $this->foreign_inherit_val 
     119            ); 
     120        } 
     121    } 
    20122     
    21123    /** 
  • trunk/Solar/Sql/Model/Related/HasOne.php

    r2933 r3107  
    1717 */ 
    1818class Solar_Sql_Model_Related_HasOne extends Solar_Sql_Model_Related { 
     19     
     20    /** 
     21     *  
     22     * When the native model is doing a select and an eager-join is requested 
     23     * for this relation, this method modifies the select to add the eager 
     24     * join. 
     25     *  
     26     * Automatically adds the foreign columns to the select. 
     27     *  
     28     * @param Solar_Sql_Select $select The SELECT to be modified. 
     29     *  
     30     * @return void The SELECT is modified in place. 
     31     *  
     32     */ 
     33    public function modSelectEager($select) 
     34    { 
     35        // build column names as "name__col" so that we can extract the 
     36        // the related data later. 
     37        $cols = array(); 
     38        foreach ($this->cols as $col) { 
     39            $cols[] = "$col AS {$this->name}__$col"; 
     40        } 
     41         
     42        $this->_modSelectEager($select, $cols); 
     43    } 
    1944     
    2045    /**