Subversion-Projekte lars-tiefland.php_share

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 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: SfPropelBehaviorI18n.php 24597 2009-11-30 19:53:50Z Kris.Wallsmith $
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
}