source: trunk/generator/classes/propel/engine/builder/om/php5/PHP5ComplexObjectBuilder.php @ 406

Revision 406, 38.6 KB checked in by hans, 4 years ago (diff)

#275 (cont.) - updated the internals of getRelated*() methods to correctly use passed-in Query in !BasePeer::doSelect()

  • Property svn:keywords set to Id Rev Date
Line 
1<?php
2
3/*
4 *  $Id$
5 *
6 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
7 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
8 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
9 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
10 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
11 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
12 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
13 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
14 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
15 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
16 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
17 *
18 * This software consists of voluntary contributions made by many individuals
19 * and is licensed under the LGPL. For more information please see
20 * <http://propel.phpdb.org>.
21 */
22
23require_once 'propel/engine/builder/om/php5/PHP5BasicObjectBuilder.php';
24
25/**
26 * Generates a PHP5 base Object class with complex object model methods.
27 *
28 * This class adds on to the PHP5BasicObjectBuilder class by adding more complex
29 * logic related to relationships to methods like the setters, and save method. Also,
30 * new get*Join*() methods are added to fetch related rows.
31 *
32 * @author Hans Lellelid <hans@xmpl.org>
33 * @package propel.engine.builder.om.php5
34 */
35class PHP5ComplexObjectBuilder extends PHP5BasicObjectBuilder {
36
37        /**
38         * Adds additional attributes used for complex object model.
39         * @param string &$script The script will be modified in this method.
40         * @see addFKAttributes()
41         * @see addRefFKAttributes()
42         * @see addAlreadyInSaveAttribute()
43         * @see addAlreadyInValidationAttribute()
44         */
45        protected function addAttributes(&$script)
46        {
47                $table = $this->getTable();
48                parent::addAttributes($script);
49
50                foreach ($table->getForeignKeys() as $fk) {
51                        $this->addFKAttributes($script, $fk);
52                }
53
54                foreach($table->getReferrers() as $refFK) {
55                        // if ($refFK->getTable()->getName() != $table->getName()) {
56                                $this->addRefFKAttributes($script, $refFK);
57                        // }
58                }
59
60                $this->addAlreadyInSaveAttribute($script);
61                $this->addAlreadyInValidationAttribute($script);
62        }
63
64        /**
65         * Specifies the methods that are added as part of the basic OM class.
66         * This can be overridden by subclasses that wish to add more methods.
67         * @param string &$script The script will be modified in this method.
68         * @see PHP5BasicObjectBuilder::addClassBody()
69         */
70        protected function addClassBody(&$script)
71        {
72                $table = $this->getTable();
73                parent::addClassBody($script);
74
75
76                $this->addFKMethods($script);
77                $this->addRefFKMethods($script);
78
79        }
80
81        /**
82         * Adds the close of mutator (setter) method for a column.
83         * This method overrides the method from PHP5BasicObjectBuilder in order to
84         * account for updating related objects.
85         * @param string &$script The script will be modified in this method.
86         * @param Column $col The current column.
87         * @see PHP5BasicObjectBuilder::addMutatorClose()
88         */
89        protected function addMutatorClose(&$script, Column $col)
90        {
91                $table = $this->getTable();
92                $cfc=$col->getPhpName();
93                $clo=strtolower($col->getName());
94
95                if ($col->isForeignKey()) {
96
97                        $tblFK = $table->getDatabase()->getTable($col->getRelatedTableName());
98                        $colFK = $tblFK->getColumn($col->getRelatedColumnName());
99
100                        $varName = $this->getFKVarName($col->getForeignKey());
101
102                        $script .= "
103                if (\$this->$varName !== null && \$this->".$varName."->get".$colFK->getPhpName()."() !== \$v) {
104                        \$this->$varName = null;
105                }
106";
107                } /* if col is foreign key */
108
109                foreach ($col->getReferrers() as $fk) {
110
111                        $tblFK = $this->getDatabase()->getTable($fk->getForeignTableName());
112
113                        if ( $tblFK->getName() != $table->getName() ) {
114
115                                $collName = $this->getRefFKCollVarName($fk);
116
117                                $tblFK = $table->getDatabase()->getTable($col->getRelatedTableName());
118                                $colFK = $tblFK->getColumn($col->getRelatedColumnName());
119
120                                $script .= "
121
122                // update associated ".$tblFK->getPhpName()."
123                if (\$this->$collName !== null) {
124                        foreach(\$this->$collName as \$referrerObject) {
125                                  \$referrerObject->set".$colFK->getPhpName()."(\$v);
126                          }
127                  }
128";
129                        } // if
130                } // foreach
131
132                $script .= "
133        } // set$cfc()
134";
135        } // addMutatorClose()
136
137        /**
138         * Adds the methods related to validating, saving and deleting the object.
139         * @param string &$script The script will be modified in this method.
140         */
141        protected function addManipulationMethods(&$script)
142        {
143                $this->addDelete($script);
144                $this->addSave($script);
145                $this->addDoSave($script);
146        }
147
148        /**
149         * Adds the methods related to validationg the object.
150         * @param string &$script The script will be modified in this method.
151         */
152        protected function addValidationMethods(&$script)
153        {
154                parent::addValidationMethods($script);
155                $this->addDoValidate($script);
156        }
157
158        /**
159         * Convenience method to get the foreign Table object for an fkey.
160         * @return Table
161         */
162        protected function getForeignTable(ForeignKey $fk)
163        {
164                return $this->getTable()->getDatabase()->getTable($fk->getForeignTableName());
165        }
166
167        /**
168         * Gets the PHP method name affix to be used for fkeys for the current table (not referrers to this table).
169         *
170         * The difference between this method and the getRefFKPhpNameAffix() method is that in this method the
171         * classname in the affix is the foreign table classname.
172         *
173         * @param ForeignKey $fk The local FK that we need a name for.
174         * @param boolean $plural Whether the php name should be plural (e.g. initRelatedObjs() vs. addRelatedObj()
175         * @return string
176         */
177        public function getFKPhpNameAffix(ForeignKey $fk, $plural = false)
178        {
179                $className = $this->getForeignTable($fk)->getPhpName();
180                return $className . ($plural ? 's' : '') . $this->getRelatedBySuffix($fk);
181        }
182
183        /**
184         * Gets the PHP method name affix to be used for referencing foreign key methods and variable names (e.g. set????(), $coll???).
185         *
186         * The difference between this method and the getFKPhpNameAffix() method is that in this method the
187         * classname in the affix is the classname of the local fkey table.
188         *
189         * @param ForeignKey $fk The referrer FK that we need a name for.
190         * @param boolean $plural Whether the php name should be plural (e.g. initRelatedObjs() vs. addRelatedObj()
191         * @return string
192         */
193        public function getRefFKPhpNameAffix(ForeignKey $fk, $plural = false)
194        {
195                $className = $fk->getTable()->getPhpName();
196                return $className . ($plural ? 's' : '') . $this->getRelatedBySuffix($fk);
197        }
198
199        /**
200         * Gets the "RelatedBy*" suffix (if needed) that is attached to method and variable names.
201         *
202         * The related by suffix is based on the local columns of the foreign key.  If there is more than
203         * one column in a table that points to the same foreign table, then a 'RelatedByLocalColName' suffix
204         * will be appended.
205         *
206         * @return string
207         */
208        protected function getRelatedBySuffix(ForeignKey $fk)
209        {
210                $relCol = "";
211                foreach ($fk->getLocalColumns() as $columnName) {
212                        $column = $fk->getTable()->getColumn($columnName);
213                        if (!$column) {
214                            $e = new Exception("Could not fetch column: $columnName in table " . $fk->getTable()->getName());
215                                print $e;
216                                throw $e;
217                        }
218                        if ($column->isMultipleFK() || $fk->getForeignTableName() == $fk->getTable()->getName()) {
219                                // if there are seeral foreign keys that point to the same table
220                                // then we need to generate methods like getAuthorRelatedByColName()
221                                // instead of just getAuthor().  Currently we are doing the same
222                                // for self-referential foreign keys, to avoid confusion.
223                                $relCol .= $column->getPhpName();
224                        }
225                }
226
227                if ($relCol != "") {
228                        $relCol = "RelatedBy" . $relCol;
229                }
230
231                return $relCol;
232        }
233
234        protected function getFKVarName(ForeignKey $fk)
235        {
236                return 'a' . $this->getFKPhpNameAffix($fk, $plural = false);
237        }
238
239        protected function getRefFKCollVarName(ForeignKey $fk)
240        {
241                return 'coll' . $this->getRefFKPhpNameAffix($fk, $plural = true);
242        }
243
244        protected function getRefFKLastCriteriaVarName(ForeignKey $fk)
245        {
246                return 'last' . $this->getRefFKPhpNameAffix($fk, $plural = false) . 'Criteria';
247        }
248
249        // ----------------------------------------------------------------
250        //
251        // F K    M E T H O D S
252        //
253        // ----------------------------------------------------------------
254
255        /**
256         * Adds the methods that get & set objects related by foreign key to the current object.
257         * @param string &$script The script will be modified in this method.
258         */
259        protected function addFKMethods(&$script)
260        {
261                foreach ($this->getTable()->getForeignKeys() as $fk) {
262                        $this->addFKMutator($script, $fk);
263                        $this->addFKAccessor($script, $fk);
264                } // foreach fk
265        }
266
267        /**
268         * Adds the class attributes that are needed to store fkey related objects.
269         * @param string &$script The script will be modified in this method.
270         */
271        protected function addFKAttributes(&$script, ForeignKey $fk)
272        {
273                $className = $this->getForeignTable($fk)->getPhpName();
274                $varName = $this->getFKVarName($fk);
275
276                $script .= "
277        /**
278         * @var $className
279         */
280        protected $".$varName.";
281";
282        }
283
284        /**
285         * Adds the mutator (setter) method for setting an fkey related object.
286         * @param string &$script The script will be modified in this method.
287         */
288        protected function addFKMutator(&$script, ForeignKey $fk)
289        {
290                $table = $this->getTable();
291                $tblFK = $this->getForeignTable($fk);
292                $className = $this->getForeignTable($fk)->getPhpName();
293                $varName = $this->getFKVarName($fk);
294
295                $script .= "
296        /**
297         * Declares an association between this object and a $className object.
298         *
299         * @param $className \$v
300         * @return void
301         * @throws PropelException
302         */
303        public function set".$this->getFKPhpNameAffix($fk, $plural = false)."(\$v)
304        {
305";
306                        foreach ($fk->getLocalColumns() as $columnName) {
307                                $column = $table->getColumn($columnName);
308                                $lfmap = $fk->getLocalForeignMapping();
309                                $colFKName = $lfmap[$columnName];
310                                $colFK = $tblFK->getColumn($colFKName);
311                                $script .= "
312
313                if (\$v === null) {
314                        \$this->set".$column->getPhpName()."(".var_export($column->getDefaultValue(), true).");
315                } else {
316                        \$this->set".$column->getPhpName()."(\$v->get".$colFK->getPhpName()."());
317                }
318";
319
320                        } /* foreach local col */
321
322                        $script .= "
323
324                \$this->$varName = \$v;
325        }
326";
327        }
328
329        /**
330         * Adds the accessor (getter) method for getting an fkey related object.
331         * @param string &$script The script will be modified in this method.
332         */
333        protected function addFKAccessor(&$script, ForeignKey $fk)
334        {
335                $table = $this->getTable();
336
337                $className = $this->getForeignTable($fk)->getPhpName();
338                $varName = $this->getFKVarName($fk);
339
340                $and = "";
341                $comma = "";
342                $conditional = "";
343                $arglist = "";
344                $argsize = 0;
345                foreach ($fk->getLocalColumns() as $columnName) {
346                        $column = $table->getColumn($columnName);
347                        $cptype = $column->getPhpNative();
348                        $clo = strtolower($column->getName());
349
350                        // FIXME: is this correct? what about negative numbers?
351                        if ($cptype == "integer" || $cptype == "float" || $cptype == "double") {
352                                $conditional .= $and . "\$this->". $clo ." > 0";
353                        } elseif($cptype == "string") {
354                                $conditional .= $and . "(\$this->" . $clo ." !== \"\" && \$this->".$clo." !== null)";
355                        } else {
356                                $conditional .= $and . "\$this->" . $clo ." !== null";
357                        }
358                        $arglist .= $comma . "\$this->" . $clo;
359                        $and = " && ";
360                        $comma = ", ";
361                        $argsize = $argsize + 1;
362                }
363
364                $pCollName = $this->getFKPhpNameAffix($fk, $plural = true);
365
366                $fkPeerBuilder = OMBuilder::getNewPeerBuilder($this->getForeignTable($fk));
367
368                $script .= "
369
370        /**
371         * Get the associated $className object
372         *
373         * @param Connection Optional Connection object.
374         * @return $className The associated $className object.
375         * @throws PropelException
376         */
377        public function get".$this->getFKPhpNameAffix($fk, $plural = false)."(\$con = null)
378        {
379                // include the related Peer class
380                include_once '".$fkPeerBuilder->getClassFilePath()."';
381
382                if (\$this->$varName === null && ($conditional)) {
383";
384                $script .= "
385                        \$this->$varName = ".$fkPeerBuilder->getPeerClassname()."::".$fkPeerBuilder->getRetrieveMethodName()."($arglist, \$con);
386
387                        /* The following can be used instead of the line above to
388                           guarantee the related object contains a reference
389                           to this object, but this level of coupling
390                           may be undesirable in many circumstances.
391                           As it can lead to a db query with many results that may
392                           never be used.
393                           \$obj = ".$fkPeerBuilder->getPeerClassname()."::retrieveByPK($arglist, \$con);
394                           \$obj->add$pCollName(\$this);
395                         */
396                }
397                return \$this->$varName;
398        }
399";
400
401        } // addFKAccessor
402
403        /**
404         * Adds a convenience method for setting a related object by specifying the primary key.
405         * This can be used in conjunction with the getPrimaryKey() for systems where nothing is known
406         * about the actual objects being related.
407         * @param string &$script The script will be modified in this method.
408         */
409        protected function addFKByKeyMutator(&$script, ForeignKey $fk)
410        {
411                $table = $this->getTable();
412
413                #$className = $this->getForeignTable($fk)->getPhpName();
414                $methodAffix = $this->getFKPhpNameAffix($fk);
415                #$varName = $this->getFKVarName($fk);
416
417                $script .= "
418        /**
419         * Provides convenient way to set a relationship based on a
420         * key.  e.g.
421         * <code>\$bar->setFooKey(\$foo->getPrimaryKey())</code>
422         *";
423                if (count($fk->getLocalColumns()) > 1) {
424                        $script .= "
425         * Note: It is important that the xml schema used to create this class
426         * maintains consistency in the order of related columns between
427         * ".$table->getName()." and ". $tblFK->getName().".
428         * If for some reason this is impossible, this method should be
429         * overridden in <code>".$table->getPhpName()."</code>.";
430                }
431                $script .= "
432         * @return void
433         * @throws PropelException
434         */
435        public function set".$methodAffix."Key(\$key)
436        {
437";
438                if (count($fk->getLocalColumns()) > 1) {
439                        $i = 0;
440                        foreach ($fk->getLocalColumns() as $colName) {
441                                $col = $table->getColumn($colName);
442                                $fktype = $col->getPhpNative();
443                                $script .= "
444                        \$this->set".$col->getPhpName()."( ($fktype) \$key[$i] );
445";
446                                $i++;
447                        } /* foreach */
448                } else {
449                        $lcols = $fk->getLocalColumns();
450                        $colName = $lcols[0];
451                        $col = $table->getColumn($colName);
452                        $fktype = $col->getPhpNative();
453                        $script .= "
454                \$this->set".$col->getPhpName()."( ($fktype) \$key);
455";
456                }
457                $script .= "
458        }
459";
460        } // addFKByKeyMutator()
461
462        /**
463         * Adds the method that fetches fkey-related (referencing) objects but also joins in data from another table.
464         * @param string &$script The script will be modified in this method.
465         */
466        protected function addRefFKGetJoinMethods(&$script, ForeignKey $refFK)
467        {
468                $table = $this->getTable();
469                $tblFK = $refFK->getTable();
470
471                $relCol = $this->getRefFKPhpNameAffix($refFK, $plural=true);
472                $collName = $this->getRefFKCollVarName($refFK);
473                $lastCriteriaName = $this->getRefFKLastCriteriaVarName($refFK);
474
475                $fkPeerBuilder = OMBuilder::getNewPeerBuilder($tblFK);
476
477                $lastTable = "";
478                foreach ($tblFK->getForeignKeys() as $fk2) {
479
480                        // Add join methods if the fk2 table is not this table or
481                        // the fk2 table references this table multiple times.
482
483                        $doJoinGet = true;
484
485                        if ( $fk2->getForeignTableName() == $table->getName() ) {
486                                $doJoinGet = false;
487                        }
488
489                        foreach ($fk2->getLocalColumns() as $columnName) {
490                                $column = $tblFK->getColumn($columnName);
491                                if ($column->isMultipleFK()) {
492                                        $doJoinGet = true;
493                                }
494                        }
495
496                        $tblFK2 = $this->getForeignTable($fk2);
497                        $doJoinGet = !$tblFK2->isForReferenceOnly();
498
499                        // it doesn't make sense to join in rows from the curent table, since we are fetching
500                        // objects related to *this* table (i.e. the joined rows will all be the same row as current object)
501                        if ($this->getTable()->getPhpName() == $tblFK2->getPhpName()) {
502                                $doJoinGet = false;
503                        }
504
505                        $relCol2 = $this->getFKPhpNameAffix($fk2, $plural = false);
506
507                        if ( $this->getRelatedBySuffix($refFK) != "" &&
508                                                        ($this->getRelatedBySuffix($refFK) == $this->getRelatedBySuffix($fk2))) {
509                                $doJoinGet = false;
510                        }
511
512                        if ($doJoinGet) {
513                                $script .= "
514
515        /**
516         * If this collection has already been initialized with
517         * an identical criteria, it returns the collection.
518         * Otherwise if this ".$table->getPhpName()." is new, it will return
519         * an empty collection; or if this ".$table->getPhpName()." has previously
520         * been saved, it will retrieve related $relCol from storage.
521         *
522         * This method is protected by default in order to keep the public
523         * api reasonable.  You can provide public methods for those you
524         * actually need in ".$table->getPhpName().".
525         */
526        public function get".$relCol."Join".$relCol2."(\$criteria = null, \$con = null)
527        {
528                // include the Peer class
529                include_once '".$fkPeerBuilder->getClassFilePath()."';
530                if (\$criteria === null) {
531                        \$criteria = new " . $this->getBuildProperty('criteriaClass') ."();
532                }
533                elseif (\$criteria instanceof Criteria)
534                {
535                        \$criteria = clone \$criteria;
536                }
537
538                if (\$this->$collName === null) {
539                        if (\$this->isNew()) {
540                                \$this->$collName = array();
541                        } else {
542";
543                                foreach ($refFK->getForeignColumns() as $columnName) {
544                                        $column = $table->getColumn($columnName);
545                                        $flMap = $refFK->getForeignLocalMapping();
546                                        $colFKName = $flMap[$columnName];
547                                        $colFK = $tblFK->getColumn($colFKName);
548                                        if ($colFK === null) {
549                                            $e = new Exception("Column $colFKName not found in " . $tblFK->getName());
550                                                print $e;
551                                                throw $e;
552                                        }
553                                        $script .= "
554                                \$criteria->add(".$fkPeerBuilder->getColumnConstant($colFK).", \$this->get".$column->getPhpName()."());
555";
556                                } // end foreach ($fk->getForeignColumns()
557
558                                $script .= "
559                                \$this->$collName = ".$fkPeerBuilder->getPeerClassname()."::doSelectJoin$relCol2(\$criteria, \$con);
560                        }
561                } else {
562                        // the following code is to determine if a new query is
563                        // called for.  If the criteria is the same as the last
564                        // one, just return the collection.
565";
566                                foreach ($refFK->getForeignColumns() as $columnName) {
567                                        $column = $table->getColumn($columnName);
568                                        $flMap = $refFK->getForeignLocalMapping();
569                                        $colFKName = $flMap[$columnName];
570                                        $colFK = $tblFK->getColumn($colFKName);
571                                        $script .= "
572                        \$criteria->add(".$fkPeerBuilder->getColumnConstant($colFK).", \$this->get".$column->getPhpName()."());
573";
574                                } /* end foreach ($fk->getForeignColumns() */
575
576                                $script .= "
577                        if (!isset(\$this->$lastCriteriaName) || !\$this->".$lastCriteriaName."->equals(\$criteria)) {
578                                \$this->$collName = ".$fkPeerBuilder->getPeerClassname()."::doSelectJoin$relCol2(\$criteria, \$con);
579                        }
580                }
581                \$this->$lastCriteriaName = \$criteria;
582
583                return \$this->$collName;
584        }
585";
586                        } /* end if($doJoinGet) */
587
588                } /* end foreach ($tblFK->getForeignKeys() as $fk2) { */
589
590        } // function
591
592
593        // ----------------------------------------------------------------
594        //
595        // R E F E R R E R    F K    M E T H O D S
596        //
597        // ----------------------------------------------------------------
598
599        /**
600         * Adds the attributes used to store objects that have referrer fkey relationships to this object.
601         * <code>protected collVarName;</code>
602         * <code>private lastVarNameCriteria = null;</code>
603         * @param string &$script The script will be modified in this method.
604         */
605        protected function addRefFKAttributes(&$script, ForeignKey $refFK)
606        {
607                $collName = $this->getRefFKCollVarName($refFK);
608                $lastCriteriaName = $this->getRefFKLastCriteriaVarName($refFK);
609
610                $script .= "
611        /**
612         * Collection to store aggregation of $collName.
613         * @var array
614         */
615        protected $".$collName.";
616
617        /**
618         * The criteria used to select the current contents of $collName.
619         * @var Criteria
620         */
621        protected \$".$lastCriteriaName." = null;
622";
623        }
624
625        /**
626         * Adds the methods for retrieving, initializing, adding objects that are related to this one by foreign keys.
627         * @param string &$script The script will be modified in this method.
628         */
629        protected function addRefFKMethods(&$script)
630        {
631                foreach($this->getTable()->getReferrers() as $refFK) {
632                        // if ( $refFK->getTable()->getName() != $this->getTable()->getName() ) {
633                                $this->addRefFKInit($script, $refFK);
634                                $this->addRefFKGet($script, $refFK);
635                                $this->addRefFKCount($script, $refFK);
636                                $this->addRefFKAdd($script, $refFK);
637                                $this->addRefFKGetJoinMethods($script, $refFK);
638                        // }
639                }
640        }
641
642        /**
643         * Adds the method that initializes the referrer fkey collection.
644         * @param string &$script The script will be modified in this method.
645         */
646        protected function addRefFKInit(&$script, ForeignKey $refFK) {
647
648                $relCol = $this->getRefFKPhpNameAffix($refFK, $plural = true);
649                $collName = $this->getRefFKCollVarName($refFK);
650
651                $script .= "
652        /**
653         * Temporary storage of $collName to save a possible db hit in
654         * the event objects are add to the collection, but the
655         * complete collection is never requested.
656         * @return void
657         */
658        public function init$relCol()
659        {
660                if (\$this->$collName === null) {
661                        \$this->$collName = array();
662                }
663        }
664";
665        } // addRefererInit()
666
667        /**
668         * Adds the method that adds an object into the referrer fkey collection.
669         * @param string &$script The script will be modified in this method.
670         */
671        protected function addRefFKAdd(&$script, ForeignKey $refFK)
672        {
673                $tblFK = $refFK->getTable();
674                $className = $refFK->getTable()->getPhpName();
675
676                $joinedTableObjectBuilder = OMBuilder::getNewObjectBuilder($refFK->getTable());
677
678                $script .= "
679        /**
680         * Method called to associate a ".$tblFK->getPhpName()." object to this object
681         * through the $className foreign key attribute
682         *
683         * @param $className \$l $className
684         * @return void
685         * @throws PropelException
686         */
687        public function add".$this->getRefFKPhpNameAffix($refFK, $plural = false)."($className \$l)
688        {
689                \$this->coll".$this->getRefFKPhpNameAffix($refFK, $plural = true)."[] = \$l;
690                \$l->set".$this->getFKPhpNameAffix($refFK, $plural = false)."(\$this);
691        }
692";
693        } // addRefererAdd
694
695        /**
696         * Adds the method that returns the size of the referrer fkey collection.
697         * @param string &$script The script will be modified in this method.
698         */
699        protected function addRefFKCount(&$script, ForeignKey $refFK)
700        {
701                $relCol = $this->getRefFKPhpNameAffix($refFK, $plural = true);
702
703                $fkPeerBuilder = OMBuilder::getNewPeerBuilder($refFK->getTable());
704
705                $script .= "
706        /**
707         * Returns the number of related $relCol.
708         *
709         * @param Criteria \$criteria
710         * @param boolean \$distinct
711         * @param Connection \$con
712         * @throws PropelException
713         */
714        public function count$relCol(\$criteria = null, \$distinct = false, \$con = null)
715        {
716                // include the Peer class
717                include_once '".$fkPeerBuilder->getClassFilePath()."';
718                if (\$criteria === null) {
719                        \$criteria = new " . $this->getBuildProperty('criteriaClass') ."();
720                }
721                elseif (\$criteria instanceof Criteria)
722                {
723                        \$criteria = clone \$criteria;
724                }
725";
726                foreach ($refFK->getForeignColumns() as $columnName) {
727                        $column = $this->getTable()->getColumn($columnName);
728                        $flmap = $refFK->getForeignLocalMapping();
729                        $colFKName = $flmap[$columnName];
730                        $colFK = $refFK->getTable()->getColumn($colFKName);
731                        $script .= "
732                \$criteria->add(".$fkPeerBuilder->getColumnConstant($colFK).", \$this->get".$column->getPhpName()."());
733";
734                } // end foreach ($fk->getForeignColumns()
735                $script .="
736                return ".$fkPeerBuilder->getPeerClassname()."::doCount(\$criteria, \$distinct, \$con);
737        }
738";
739        } // addRefererCount
740
741        /**
742         * Adds the method that returns the referrer fkey collection.
743         * @param string &$script The script will be modified in this method.
744         */
745        protected function addRefFKGet(&$script, ForeignKey $refFK)
746        {
747                $table = $this->getTable();
748                $tblFK = $refFK->getTable();
749
750                $fkPeerBuilder = OMBuilder::getNewPeerBuilder($refFK->getTable());
751                $relCol = $this->getRefFKPhpNameAffix($refFK, $plural = true);
752
753                $collName = $this->getRefFKCollVarName($refFK);
754                $lastCriteriaName = $this->getRefFKLastCriteriaVarName($refFK);
755
756                $script .= "
757        /**
758         * If this collection has already been initialized with
759         * an identical criteria, it returns the collection.
760         * Otherwise if this ".$table->getPhpName()." has previously
761         * been saved, it will retrieve related $relCol from storage.
762         * If this ".$table->getPhpName()." is new, it will return
763         * an empty collection or the current collection, the criteria
764         * is ignored on a new object.
765         *
766         * @param Query \$query An optional Query object to filter results.
767         * @param PDO \$con
768         * @throws PropelException
769         */
770        public function get$relCol(Query \$query = null, PDO \$con = null)
771        {
772                // include the Peer class
773                include_once '".$fkPeerBuilder->getClassFilePath()."';
774                if (\$query === null) {
775                        \$query = ".$fkPeerBuilder->getPeerClassname()."::createQuery();
776                } else {
777                        \$query = clone \$query;
778                }
779               
780                \$criteria = \$query->getCriteria();
781               
782                if (\$this->$collName === null) {
783                        if (\$this->isNew()) {
784                           \$this->$collName = array();
785                        } else {
786";
787                foreach ($refFK->getLocalColumns() as $colFKName) {
788                        // $colFKName is local to the referring table (i.e. foreign to this table)
789                        $lfmap = $refFK->getLocalForeignMapping();
790                        $localColumn = $this->getTable()->getColumn($lfmap[$colFKName]);
791                        $colFK = $refFK->getTable()->getColumn($colFKName);
792
793                        $script .= "
794                                \$criteria->add(new EqualExpr(".$fkPeerBuilder->getColumnConstant($colFK).", \$this->get".$localColumn->getPhpName()."()));
795";
796                } // end foreach ($fk->getForeignColumns()
797
798                $script .= "
799                                \$query->addSelectColumnsForTable(".$fkPeerBuilder->getPeerClassname()."::createQueryTable());
800                                // ".$fkPeerBuilder->getPeerClassname()."::addSelectColumns(\$criteria);
801                                \$this->$collName = ".$fkPeerBuilder->getPeerClassname()."::doSelect(\$query, \$con);
802                        }
803                } else {
804                        // criteria has no effect for a new object
805                        if (!\$this->isNew()) {
806                                // the following code is to determine if a new query is
807                                // called for.  If the criteria is the same as the last
808                                // one, just return the collection.
809";
810                foreach ($refFK->getLocalColumns() as $colFKName) {
811                        // $colFKName is local to the referring table (i.e. foreign to this table)
812                        $lfmap = $refFK->getLocalForeignMapping();
813                        $localColumn = $this->getTable()->getColumn($lfmap[$colFKName]);
814                        $colFK = $refFK->getTable()->getColumn($colFKName);
815                        $script .= "
816
817                                \$criteria->add(new EqualExpr(".$fkPeerBuilder->getColumnConstant($colFK).", \$this->get".$localColumn->getPhpName()."()));
818";
819        } // foreach ($fk->getForeignColumns()
820$script .= "
821
822                                \$query->addSelectColumnsForTable(".$fkPeerBuilder->getPeerClassname()."::createQueryTable());
823                                // ".$fkPeerBuilder->getPeerClassname()."::addSelectColumns(\$criteria);
824                                if (!isset(\$this->$lastCriteriaName) || !\$this->".$lastCriteriaName." == \$criteria) { // FIXME <- implement equals()
825                                        \$this->$collName = ".$fkPeerBuilder->getPeerClassname()."::doSelect(\$query, \$con);
826                                }
827                        }
828                }
829                \$this->$lastCriteriaName = \$criteria;
830                return \$this->$collName;
831        }
832";
833        } // addRefererGet()
834
835
836
837        // ----------------------------------------------------------------
838        //
839        // M A N I P U L A T I O N    M E T H O D S
840        //
841        // ----------------------------------------------------------------
842
843        /**
844         * Adds the workhourse doSave() method.
845         * @param string &$script The script will be modified in this method.
846         */
847        protected function addDoSave(&$script)
848        {
849                $table = $this->getTable();
850
851                $script .= "
852        /**
853         * Stores the object in the database.
854         *
855         * If the object is new, it inserts it; otherwise an update is performed.
856         * All related objects are also updated in this method.
857         *
858         * @param Connection \$con
859         * @return int The number of rows affected by this insert/update and any referring fk objects' save() operations.
860         * @throws PropelException
861         * @see save()
862         */
863        protected function doSave(\$con)
864        {
865                \$affectedRows = 0; // initialize var to track total num of affected rows
866                if (!\$this->alreadyInSave) {
867                        \$this->alreadyInSave = true;
868";
869
870                if (count($table->getForeignKeys())) {
871
872                        $script .= "
873
874                        // We call the save method on the following object(s) if they
875                        // were passed to this object by their coresponding set
876                        // method.  This object relates to these object(s) by a
877                        // foreign key reference.
878";
879
880                        foreach($table->getForeignKeys() as $fk)
881                        {
882                                $aVarName = $this->getFKVarName($fk);
883                                $script .= "
884                        if (\$this->$aVarName !== null) {
885                                if (\$this->".$aVarName."->isModified()) {
886                                        \$affectedRows += \$this->".$aVarName."->save(\$con);
887                                }
888                                \$this->set".$this->getFKPhpNameAffix($fk, $plural = false)."(\$this->$aVarName);
889                        }
890";
891                        } // foreach foreign k
892                } // if (count(foreign keys))
893
894                $script .= "
895
896                        // If this object has been modified, then save it to the database.
897                        if (\$this->isModified()";
898
899                /*
900                FIXME: this doesn't work right now because the BasePeer::doInsert() method
901                expects to be passed a Criteria object that contains columns (which tell BasePeer
902                which table is being updated)
903                if ($table->hasAutoIncrementPrimaryKey()) {
904                        $script .= " || \$this->isNew()";
905                }
906                */
907
908                $script .= ") {
909                                if (\$this->isNew()) {
910                                        \$pk = ".$this->getPeerClassname()."::doInsert(\$this, \$con);
911                                        \$affectedRows += 1; // we are assuming that there is only 1 row per doInsert() which
912                                                                                 // should always be true here (even though technically
913                                                                                 // BasePeer::doInsert() can insert multiple rows).
914";
915                if ($table->getIdMethod() != IDMethod::NO_ID_METHOD) {
916
917                        if (count($pks = $table->getPrimaryKey())) {
918                                foreach ($pks as $pk) {
919                                        if ($pk->isAutoIncrement()) {
920                                                $script .= "
921                                        \$this->set".$pk->getPhpName()."(\$pk);  //[IMV] update autoincrement primary key
922";
923                                        }
924                                }
925                        }
926                } // if (id method != "none")
927
928                $script .= "
929                                        \$this->setNew(false);
930                                } else {
931                                        \$affectedRows += ".$this->getPeerClassname()."::doUpdate(\$this, \$con);
932                                }
933                                \$this->resetModified(); // [HL] After being saved an object is no longer 'modified'
934                        }
935";
936
937                foreach ($table->getReferrers() as $fk) {
938                        $collName = $this->getRefFKCollVarName($fk);
939                        //HL: commenting out self-referrential check below
940                        //              it seems to work as expected and is desireable since we are also enabling the copy()ing of these related rows
941                        //if ( $fk->getTable()->getName() != $table->getName() ) {
942                                $script .= "
943                        if (\$this->$collName !== null) {
944                                foreach(\$this->$collName as \$referrerFK) {
945                                        if (!\$referrerFK->isDeleted()) {
946                                                \$affectedRows += \$referrerFK->save(\$con);
947                                        }
948                                }
949                        }
950";
951                        //HL: commenting out close of self-referrential check
952                        //} /* if tableFK != table */
953                } /* foreach getReferrers() */
954                $script .= "
955                        \$this->alreadyInSave = false;
956                }
957                return \$affectedRows;
958        } // doSave()
959";
960
961        }
962
963        /**
964         * Adds the $alreadyInSave attribute, which prevents attempting to re-save the same object.
965         * @param string &$script The script will be modified in this method.
966         */
967        protected function addAlreadyInSaveAttribute(&$script)
968        {
969                $script .= "
970        /**
971         * Flag to prevent endless save loop, if this object is referenced
972         * by another object which falls in this transaction.
973         * @var boolean
974         */
975        protected \$alreadyInSave = false;
976";
977        }
978
979        /**
980         * Adds the save() method.
981         * @param string &$script The script will be modified in this method.
982         */
983        protected function addSave(&$script)
984        {
985                $script .= "
986        /**
987         * Stores the object in the database.  If the object is new,
988         * it inserts it; otherwise an update is performed.  This method
989         * wraps the doSave() worker method in a transaction.
990         *
991         * @param Connection \$con
992         * @return int The number of rows affected by this insert/update and any referring fk objects' save() operations.
993         * @throws PropelException
994         * @see doSave()
995         */
996        public function save(\$con = null)
997        {
998                if (\$this->isDeleted()) {
999                        throw new PropelException(\"You cannot save an object that has been deleted.\");
1000                }
1001
1002                if (\$con === null) {
1003                        \$con = Propel::getConnection(".$this->getPeerClassname()."::DATABASE_NAME);
1004                }
1005
1006                try {
1007                        Transaction::begin(\$con);
1008                        \$affectedRows = \$this->doSave(\$con);
1009                        Transaction::commit(\$con);
1010                        return \$affectedRows;
1011                } catch (PropelException \$e) {
1012                        Transaction::rollback(\$con);
1013                        throw \$e;
1014                }
1015        }
1016";
1017
1018        }
1019
1020        /**
1021         * Adds the $alreadyInValidation attribute, which prevents attempting to re-validate the same object.
1022         * @param string &$script The script will be modified in this method.
1023         */
1024        protected function addAlreadyInValidationAttribute(&$script)
1025        {
1026                $script .= "
1027        /**
1028         * Flag to prevent endless validation loop, if this object is referenced
1029         * by another object which falls in this transaction.
1030         * @var boolean
1031         */
1032        protected \$alreadyInValidation = false;
1033";
1034        }
1035
1036        /**
1037         * Adds the validate() method.
1038         * @param string &$script The script will be modified in this method.
1039         */
1040        protected function addValidate(&$script)
1041        {
1042                $script .= "
1043        /**
1044         * Validates the objects modified field values and all objects related to this table.
1045         *
1046         * If \$columns is either a column name or an array of column names
1047         * only those columns are validated.
1048         *
1049         * @param mixed \$columns Column name or an array of column names.
1050         * @return boolean Whether all columns pass validation.
1051         * @see doValidate()
1052         * @see getValidationFailures()
1053         */
1054        public function validate(\$columns = null)
1055        {
1056                \$res = \$this->doValidate(\$columns);
1057                if (\$res === true) {
1058                        \$this->validationFailures = array();
1059                        return true;
1060                } else {
1061                        \$this->validationFailures = \$res;
1062                        return false;
1063                }
1064        }
1065";
1066        } // addValidate()
1067
1068        /**
1069         * Adds the workhourse doValidate() method.
1070         * @param string &$script The script will be modified in this method.
1071         */
1072        protected function addDoValidate(&$script)
1073        {
1074                $table = $this->getTable();
1075
1076                $script .= "
1077        /**
1078         * This function performs the validation work for complex object models.
1079         *
1080         * In addition to checking the current object, all related objects will
1081         * also be validated.  If all pass then <code>true</code> is returned; otherwise
1082         * an aggreagated array of ValidationFailed objects will be returned.
1083         *
1084         * @param array \$columns Array of column names to validate.
1085         * @return mixed <code>true</code> if all validations pass; array of <code>ValidationFailed</code> objets otherwise.
1086         */
1087        protected function doValidate(\$columns = null)
1088        {
1089                if (!\$this->alreadyInValidation) {
1090                        \$this->alreadyInValidation = true;
1091                        \$retval = null;
1092
1093                        \$failureMap = array();
1094";
1095                if (count($table->getForeignKeys()) != 0) {
1096                        $script .= "
1097
1098                        // We call the validate method on the following object(s) if they
1099                        // were passed to this object by their coresponding set
1100                        // method.  This object relates to these object(s) by a
1101                        // foreign key reference.
1102";
1103                        foreach($table->getForeignKeys() as $fk) {
1104                                $aVarName = $this->getFKVarName($fk);
1105                                $script .= "
1106                        if (\$this->".$aVarName." !== null) {
1107                                if (!\$this->".$aVarName."->validate(\$columns)) {
1108                                        \$failureMap = array_merge(\$failureMap, \$this->".$aVarName."->getValidationFailures());
1109                                }
1110                        }
1111";
1112                        } /* for() */
1113                } /* if count(fkeys) */
1114
1115                $script .= "
1116
1117                        if ((\$retval = ".$this->getPeerClassname()."::doValidate(\$this, \$columns)) !== true) {
1118                                \$failureMap = array_merge(\$failureMap, \$retval);
1119                        }
1120
1121";
1122
1123                foreach ($table->getReferrers() as $fk) {
1124                        $tblFK = $fk->getTable();
1125                        if ( $tblFK->getName() != $table->getName() ) {
1126                                $collName = $this->getRefFKCollVarName($fk);
1127                                $script .= "
1128                                if (\$this->$collName !== null) {
1129                                        foreach(\$this->$collName as \$referrerFK) {
1130                                                if (!\$referrerFK->validate(\$columns)) {
1131                                                        \$failureMap = array_merge(\$failureMap, \$referrerFK->getValidationFailures());
1132                                                }
1133                                        }
1134                                }
1135";
1136                        } /* if tableFK !+ table */
1137                } /* foreach getReferrers() */
1138
1139                $script .= "
1140
1141                        \$this->alreadyInValidation = false;
1142                }
1143
1144                return (!empty(\$failureMap) ? \$failureMap : true);
1145        }
1146";
1147        } // addDoValidate()
1148
1149        /**
1150         * Adds the copy() method, which (in complex OM) includes the $deepCopy param for making copies of related objects.
1151         * @param string &$script The script will be modified in this method.
1152         */
1153        protected function addCopy(&$script)
1154        {
1155                $this->addCopyInto($script);
1156
1157                $table = $this->getTable();
1158
1159                $script .= "
1160        /**
1161         * Makes a copy of this object that will be inserted as a new row in table when saved.
1162         * It creates a new object filling in the simple attributes, but skipping any primary
1163         * keys that are defined for the table.
1164         *
1165         * If desired, this method can also make copies of all associated (fkey referrers)
1166         * objects.
1167         *
1168         * @param boolean \$deepCopy Whether to also copy all rows that refer (by fkey) to the current row.
1169         * @return ".$table->getPhpName()." Clone of current object.
1170         * @throws PropelException
1171         */
1172        public function copy(\$deepCopy = false)
1173        {
1174                // we use get_class(), because this might be a subclass
1175                \$clazz = get_class(\$this);
1176                \$copyObj = new \$clazz();
1177                \$this->copyInto(\$copyObj, \$deepCopy);
1178                return \$copyObj;
1179        }
1180";
1181        } // addCopy()
1182
1183        /**
1184         * Adds the copyInto() method, which takes an object and sets contents to match current object.
1185         * In complex OM this method includes the $deepCopy param for making copies of related objects.
1186         * @param string &$script The script will be modified in this method.
1187         */
1188        protected function addCopyInto(&$script)
1189        {
1190                $table = $this->getTable();
1191
1192                $script .= "
1193        /**
1194         * Sets contents of passed object to values from current object.
1195         *
1196         * If desired, this method can also make copies of all associated (fkey referrers)
1197         * objects.
1198         *
1199         * @param object \$copyObj An object of ".$table->getPhpName()." (or compatible) type.
1200         * @param boolean \$deepCopy Whether to also copy all rows that refer (by fkey) to the current row.
1201         * @throws PropelException
1202         */
1203        public function copyInto(\$copyObj, \$deepCopy = false)
1204        {
1205";
1206
1207                $pkcols = array();
1208                foreach ($table->getColumns() as $pkcol) {
1209                        if ($pkcol->isPrimaryKey()) {
1210                                $pkcols[] = $pkcol->getName();
1211                        }
1212                }
1213
1214                foreach ($table->getColumns() as $col) {
1215                        if (!in_array($col->getName(), $pkcols)) {
1216                                $script .= "
1217                \$copyObj->set".$col->getPhpName()."(\$this->".strtolower($col->getName()).");
1218";
1219                        }
1220                } // foreach
1221
1222                // Avoid useless code by checking to see if there are any referrers
1223                // to this table:
1224                if (count($table->getReferrers()) > 0) {
1225                        $script .= "
1226
1227                if (\$deepCopy) {
1228                        // important: temporarily setNew(false) because this affects the behavior of
1229                        // the getter/setter methods for fkey referrer objects.
1230                        \$copyObj->setNew(false);
1231";
1232                        foreach ($table->getReferrers() as $fk) {
1233                                // Continue if $this and $copyObj are the same class and have the same primary key
1234                                // to avoid endless loops
1235                                $script .= "
1236                        foreach(\$this->get".$this->getRefFKPhpNameAffix($fk, true)."() as \$relObj) {";
1237                                if ($table->getName() === $fk->getTableName()) {
1238                                        $script .= "
1239                                if(\$this->getPrimaryKey() === \$relObj->getPrimaryKey()) {
1240                                                continue;
1241                                }
1242";
1243                                }
1244                                $script .= "
1245                                \$copyObj->add".$this->getRefFKPhpNameAffix($fk)."(\$relObj->copy(\$deepCopy));
1246                        }
1247";
1248                                // HL: commenting out close of self-referential check
1249                                // } /* if tblFK != table */
1250                        } /* foreach */
1251                        $script .= "
1252                } // if (\$deepCopy)
1253";
1254                } /* if (count referrers > 0 ) */
1255
1256                $script .= "
1257
1258                \$copyObj->setNew(true);
1259";
1260
1261
1262                foreach ($table->getColumns() as $col) {
1263                        if ($col->isPrimaryKey()) {
1264                                $coldefval = $col->getPhpDefaultValue();
1265                                $coldefval = var_export($coldefval, true);
1266                                $script .= "
1267                \$copyObj->set".$col->getPhpName() ."($coldefval); // this is a pkey column, so set to default value
1268";
1269                        } // if col->isPrimaryKey
1270                } // foreach
1271                $script .= "
1272        }
1273";
1274        } // addCopyInto()
1275
1276} // PHP5ComplexObjectBuilder
Note: See TracBrowser for help on using the repository browser.