Development

/branches/1.4/lib/plugins/sfPropelPlugin/lib/behavior/SfPropelBehaviorI18n.php

You must first sign up to be able to contribute.

root/branches/1.4/lib/plugins/sfPropelPlugin/lib/behavior/SfPropelBehaviorI18n.php

Revision 24597, 10.4 kB (checked in by Kris.Wallsmith, 5 years ago)

[1.3, 1.4] fixed casting of propel i18n objects to string (closes #7709)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
Line 
1 <?php
2
3 /*
4  * This file is part of the symfony package.
5  * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
6  *
7  * For the full copyright and license information, please view the LICENSE
8  * file that was distributed with this source code.
9  */
10
11 /**
12  * Internationalizes Propel models.
13  *
14  * This behavior is intended to be applied at the database level.
15  *
16  * @package     sfPropelPlugin
17  * @subpackage  behavior
18  * @author      Kris Wallsmith <kris.wallsmith@symfony-project.com>
19  * @version     SVN: $Id$
20  */
21 class SfPropelBehaviorI18n extends SfPropelBehaviorBase
22 {
23   protected $parameters = array(
24     'i18n_table' => null,
25   );
26
27   /**
28    * Looks for tables marked as I18N and adds behaviors.
29    */
30   public function modifyDatabase()
31   {
32     $translationBehavior = Propel::importClass($this->getBuildProperty('propel.behavior.symfony_i18n_translation.class'));
33
34     foreach ($this->getDatabase()->getTables() as $table)
35     {
36       $behaviors = $table->getBehaviors();
37
38       if (!isset($behaviors['symfony_i18n']) && 'true' == $table->getAttribute('isI18N'))
39       {
40         $i18nTable = $this->getDatabase()->getTable($table->getAttribute('i18nTable'));
41
42         // add the current behavior to the translatable model
43         $behavior = clone $this;
44         $behavior->setParameters(array('i18n_table' => $i18nTable->getName()));
45         $table->addBehavior($behavior);
46
47         // add the translation behavior to the translation model
48         $behavior = new $translationBehavior();
49         $behavior->setName('symfony_i18n_translation');
50         $behavior->setParameters(array('culture_column' => $this->getCultureColumn($i18nTable)->getName()));
51         $i18nTable->addBehavior($behavior);
52       }
53     }
54   }
55
56   public function modifyTable()
57   {
58     if ($this->isDisabled())
59     {
60       return;
61     }
62
63     if (count($this->getTable()->getPrimaryKey()) > 1)
64     {
65       throw new Exception('i18n support only works with a single primary key');
66     }
67   }
68
69   public function objectAttributes()
70   {
71     if ($this->isDisabled())
72     {
73       return;
74     }
75
76     return <<<EOF
77
78 /**
79  * @var string The value for the culture field
80  */
81 protected \$culture = null;
82
83 /**
84  * @var array Current I18N objects
85  */
86 protected \$current_i18n = array();
87
88 EOF;
89   }
90
91   public function objectMethods()
92   {
93     if ($this->isDisabled())
94     {
95       return;
96     }
97
98     $script = <<<EOF
99
100 /**
101  * Returns the culture.
102  *
103  * @return string The culture
104  */
105 public function getCulture()
106 {
107   return \$this->culture;
108 }
109
110 /**
111  * Sets the culture.
112  *
113  * @param string $culture The culture to set
114  *
115  * @return {$this->getTable()->getPhpName()}
116  */
117 public function setCulture(\$culture)
118 {
119   \$this->culture = \$culture;
120   return \$this;
121 }
122
123 EOF;
124
125     // add accessors and mutators for each of the i18nTable's columns
126     $foreignKey = $this->getI18nTable()->getBehavior('symfony_i18n_translation')->getForeignKey();
127     $refPhpName = $foreignKey->getRefPhpName() ? $foreignKey->getRefPhpName() : $this->getI18nTable()->getPhpName();
128
129     foreach ($this->getI18nTable()->getColumns() as $column)
130     {
131       if ($column->isPrimaryKey())
132       {
133         continue;
134       }
135
136       $script .= <<<EOF
137
138 /**
139  * Returns the "{$column->getName()}" value from the current {@link {$this->getI18nTable()->getPhpName()}}.
140  */
141 public function get{$column->getPhpName()}(\$culture = null)
142 {
143   return \$this->getCurrent{$refPhpName}(\$culture)->get{$column->getPhpName()}();
144 }
145
146 /**
147  * Sets the "{$column->getName()}" value of the current {@link {$this->getI18nTable()->getPhpName()}}.
148  *
149  * @return {$this->getTable()->getPhpName()}
150  */
151 public function set{$column->getPhpName()}(\$value, \$culture = null)
152 {
153   \$this->getCurrent{$refPhpName}(\$culture)->set{$column->getPhpName()}(\$value);
154   return \$this;
155 }
156
157 EOF;
158     }
159
160     $script .= <<<EOF
161
162 /**
163  * Returns the current translation.
164  *
165  * @return {$this->getI18nTable()->getPhpName()}
166  */
167 public function getCurrent{$refPhpName}(\$culture = null)
168 {
169   if (null === \$culture)
170   {
171     \$culture = null === \$this->culture ? sfPropel::getDefaultCulture() : \$this->culture;
172   }
173
174   if (!isset(\$this->current_i18n[\$culture]))
175   {
176     \$object = \$this->isNew() ? null : {$this->getI18nTable()->getPhpName()}Peer::retrieveByPK(\$this->getPrimaryKey(), \$culture);
177     if (\$object)
178     {
179       \$this->set{$refPhpName}ForCulture(\$object, \$culture);
180     }
181     else
182     {
183       \$this->set{$refPhpName}ForCulture(new {$this->getI18nTable()->getPhpName()}(), \$culture);
184       \$this->current_i18n[\$culture]->set{$this->getI18nTable()->getBehavior('symfony_i18n_translation')->getCultureColumn()->getPhpName()}(\$culture);
185     }
186   }
187
188   return \$this->current_i18n[\$culture];
189 }
190
191 /**
192  * Sets the translation object for a culture.
193  */
194 public function set{$refPhpName}ForCulture({$this->getI18nTable()->getPhpName()} \$object, \$culture)
195 {
196   \$this->current_i18n[\$culture] = \$object;
197   \$this->add{$refPhpName}(\$object);
198 }
199
200 EOF;
201
202     if (!$this->hasPrimaryString($this->getTable()) && $this->hasPrimaryString($this->getI18nTable()))
203     {
204       $script .= <<<EOF
205
206 /**
207  * @see {$this->getI18nTable()->getPhpName()}
208  */
209 public function __toString()
210 {
211   return (string) \$this->getCurrent{$refPhpName}();
212 }
213
214 EOF;
215     }
216
217     return $script;
218   }
219
220   public function staticMethods()
221   {
222     $foreignKey = $this->getI18nTable()->getBehavior('symfony_i18n_translation')->getForeignKey();
223     $refPhpName = $foreignKey->getRefPhpName() ? $foreignKey->getRefPhpName() : $this->getI18nTable()->getPhpName();
224     $join = in_array($this->getBuildProperty('propel.useLeftJoinsInDoJoinMethods'), array(true, null), true) ? 'LEFT' : 'INNER';
225
226     $behaviors = $this->getTable()->getBehaviors();
227     $mixerHook = !isset($behaviors['symfony_behaviors']) ? '' : <<<EOF
228
229   foreach (sfMixer::getCallables('Base{$this->getTable()->getPhpName()}:doSelectJoin:doSelectJoin') as \$sf_hook)
230   {
231     call_user_func(\$sf_hook, '{$this->getTable()->getPhpName()}', \$criteria, \$con);
232   }
233
234 EOF;
235
236     return <<<EOF
237
238 /**
239  * Returns the i18n model class name.
240  *
241  * @return string The i18n model class name
242  */
243 static public function getI18nModel()
244 {
245   return '{$this->getI18nTable()->getPhpName()}';
246 }
247
248 /**
249  * Selects a collection of {@link {$this->getTable()->getPhpName()}} objects with a {@link {$this->getI18nTable()->getPhpName()}} translation populated.
250  *
251  * @param Criteria  \$criteria
252  * @param string    \$culture
253  * @param PropelPDO \$con
254  * @param string    \$join_behavior
255  *
256  * @return array
257  */
258 static public function doSelectWithI18n(Criteria \$criteria, \$culture = null, \$con = null, \$join_behavior = Criteria::{$join}_JOIN)
259 {
260   \$criteria = clone \$criteria;
261
262   if (null === \$culture)
263   {
264     \$culture = sfPropel::getDefaultCulture();
265   }
266
267   // Set the correct dbName if it has not been overridden
268   if (\$criteria->getDbName() == Propel::getDefaultDB()) {
269       \$criteria->setDbName(self::DATABASE_NAME);
270   }
271
272   {$this->getTable()->getPhpName()}Peer::addSelectColumns(\$criteria);
273   \$startcol = ({$this->getTable()->getPhpName()}Peer::NUM_COLUMNS - {$this->getTable()->getPhpName()}Peer::NUM_LAZY_LOAD_COLUMNS);
274   {$this->getI18nTable()->getPhpName()}Peer::addSelectColumns(\$criteria);
275   \$criteria->addJoin({$this->getLocalColumn()->getConstantName()}, {$this->getForeignColumn()->getConstantName()}, \$join_behavior);
276   \$criteria->add({$this->getCultureColumn($this->getI18nTable())->getConstantName()}, \$culture);
277 {$mixerHook}
278   \$stmt = BasePeer::doSelect(\$criteria, \$con);
279     \$results = array();
280
281     while (\$row = \$stmt->fetch(PDO::FETCH_NUM)) {
282         \$key1 = {$this->getTable()->getPhpName()}Peer::getPrimaryKeyHashFromRow(\$row, 0);
283         if (null !== (\$obj1 = {$this->getTable()->getPhpName()}Peer::getInstanceFromPool(\$key1))) {
284             // We no longer rehydrate the object, since this can cause data loss.
285           // See http://propel.phpdb.org/trac/ticket/509
286           // \$obj1->hydrate(\$row, 0, true); // rehydrate
287       } else {
288             \$cls = {$this->getTable()->getPhpName()}Peer::getOMClass(false);
289             \$obj1 = new \$cls();
290             \$obj1->hydrate(\$row);
291       {$this->getTable()->getPhpName()}Peer::addInstanceToPool(\$obj1, \$key1);
292         } // if \$obj1 already loaded
293
294         \$key2 = {$this->getI18nTable()->getPhpName()}Peer::getPrimaryKeyHashFromRow(\$row, \$startcol);
295         if (\$key2 !== null) {
296             \$obj2 = {$this->getI18nTable()->getPhpName()}Peer::getInstanceFromPool(\$key2);
297             if (!\$obj2) {
298                 \$cls = {$this->getI18nTable()->getPhpName()}Peer::getOMClass(false);
299                 \$obj2 = new \$cls();
300                 \$obj2->hydrate(\$row, \$startcol);
301                 {$this->getI18nTable()->getPhpName()}Peer::addInstanceToPool(\$obj2, \$key2);
302             } // if obj2 already loaded
303
304       \$obj1->set{$refPhpName}ForCulture(\$obj2, \$culture);
305         } // if joined row was not null
306
307         \$results[] = \$obj1;
308     }
309
310     \$stmt->closeCursor();
311
312     return \$results;
313 }
314
315 EOF;
316   }
317
318   /**
319    * Returns the current table's i18n translation table.
320    *
321    * @return Table
322    */
323   public function getI18nTable()
324   {
325     return $this->getDatabase()->getTable($this->getParameter('i18n_table'));
326   }
327
328   /**
329    * Finds the supplied translation table's culture column.
330    *
331    * @return Column
332    *
333    * @throws InvalidArgumentException If there is not a column marked as "isCulture"
334    */
335   protected function getCultureColumn(Table $table)
336   {
337     foreach ($table->getColumns() as $column)
338     {
339       if ('true' == $column->getAttribute('isCulture'))
340       {
341         return $column;
342       }
343     }
344
345     throw new InvalidArgumentException(sprintf('The table "%s" does not have a column marked with the "isCulture" attribute.', $table->getName()));
346   }
347
348   /**
349    * Returns the column on the current model referenced by the translation model.
350    *
351    * @return Column
352    */
353   protected function getLocalColumn()
354   {
355     $columns = $this->getI18nTable()->getBehavior('symfony_i18n_translation')->getForeignKey()->getForeignColumns();
356     return $this->getTable()->getColumn($columns[0]);
357   }
358
359   /**
360    * Returns the column on the translation table the references the current model.
361    *
362    * @return Column
363    */
364   protected function getForeignColumn()
365   {
366     $columns = $this->getI18nTable()->getBehavior('symfony_i18n_translation')->getForeignKey()->getLocalColumns();
367     return $this->getI18nTable()->getColumn($columns[0]);
368   }
369
370   /**
371    * Checks whether the supplied table has a primary string defined.
372    *
373    * @param  Table $table
374    *
375    * @return boolean
376    */
377   protected function hasPrimaryString(Table $table)
378   {
379     foreach ($table->getColumns() as $column)
380     {
381       if ($column->isPrimaryString())
382       {
383         return true;
384       }
385     }
386
387     return false;
388   }
389 }
390
Note: See TracBrowser for help on using the browser.