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
 * (c) Jonathan H. Wage <jonwage@gmail.com>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
 
12
/**
13
 * sfFormDoctrine is the base class for forms based on Doctrine objects.
14
 *
15
 * This class extends BaseForm, a class generated automatically with each new project.
16
 *
17
 * @package    symfony
18
 * @subpackage form
19
 * @author     Fabien Potencier <fabien.potencier@symfony-project.com>
20
 * @author     Jonathan H. Wage <jonwage@gmail.com>
21
 * @version    SVN: $Id: sfFormDoctrine.class.php 32740 2011-07-09 09:24:03Z fabien $
22
 */
23
abstract class sfFormDoctrine extends sfFormObject
24
{
25
  /**
26
   * Constructor.
27
   *
28
   * @param mixed  A object used to initialize default values
29
   * @param array  An array of options
30
   * @param string A CSRF secret (false to disable CSRF protection, null to use the global CSRF secret)
31
   *
32
   * @see sfForm
33
   */
34
  public function __construct($object = null, $options = array(), $CSRFSecret = null)
35
  {
36
    $class = $this->getModelName();
37
    if (!$object)
38
    {
39
      $this->object = new $class();
40
    }
41
    else
42
    {
43
      if (!$object instanceof $class)
44
      {
45
        throw new sfException(sprintf('The "%s" form only accepts a "%s" object.', get_class($this), $class));
46
      }
47
 
48
      $this->object = $object;
49
      $this->isNew = !$this->getObject()->exists();
50
    }
51
 
52
    parent::__construct(array(), $options, $CSRFSecret);
53
 
54
    $this->updateDefaultsFromObject();
55
  }
56
 
57
  /**
58
   * @return Doctrine_Connection
59
   * @see sfFormObject
60
   */
61
  public function getConnection()
62
  {
63
    return Doctrine_Manager::getInstance()->getConnectionForComponent($this->getModelName());
64
  }
65
 
66
  /**
67
   * Embeds i18n objects into the current form.
68
   *
69
   * @param array   $cultures   An array of cultures
70
   * @param string  $decorator  A HTML decorator for the embedded form
71
   */
72
  public function embedI18n($cultures, $decorator = null)
73
  {
74
    if (!$this->isI18n())
75
    {
76
      throw new sfException(sprintf('The model "%s" is not internationalized.', $this->getModelName()));
77
    }
78
 
79
    $class = $this->getI18nFormClass();
80
    foreach ($cultures as $culture)
81
    {
82
      $i18nObject = $this->getObject()->Translation[$culture];
83
      $i18n = new $class($i18nObject);
84
 
85
      if (false === $i18nObject->exists())
86
      {
87
        unset($i18n[$this->getI18nModelPrimaryKeyName()], $i18n[$this->getI18nModelI18nField()]);
88
      }
89
 
90
      $this->embedForm($culture, $i18n, $decorator);
91
    }
92
  }
93
 
94
  /**
95
   * Embed a Doctrine_Collection relationship in to a form
96
   *
97
   *     [php]
98
   *     $userForm = new UserForm($user);
99
   *     $userForm->embedRelation('Groups AS groups');
100
   *
101
   * @param  string $relationName  The name of the relation and an optional alias
102
   * @param  string $formClass     The name of the form class to use
103
   * @param  array  $formArguments Arguments to pass to the constructor (related object will be shifted onto the front)
104
   * @param string  $innerDecorator A HTML decorator for each embedded form
105
   * @param string  $decorator      A HTML decorator for the main embedded form
106
   *
107
   * @throws InvalidArgumentException If the relationship is not a collection
108
   */
109
  public function embedRelation($relationName, $formClass = null, $formArgs = array(), $innerDecorator = null, $decorator = null)
110
  {
111
    if (false !== $pos = stripos($relationName, ' as '))
112
    {
113
      $fieldName = substr($relationName, $pos + 4);
114
      $relationName = substr($relationName, 0, $pos);
115
    }
116
    else
117
    {
118
      $fieldName = $relationName;
119
    }
120
 
121
    $relation = $this->getObject()->getTable()->getRelation($relationName);
122
 
123
    $r = new ReflectionClass(null === $formClass ? $relation->getClass().'Form' : $formClass);
124
 
125
    if (Doctrine_Relation::ONE == $relation->getType())
126
    {
127
      $this->embedForm($fieldName, $r->newInstanceArgs(array_merge(array($this->getObject()->$relationName), $formArgs)), $decorator);
128
    }
129
    else
130
    {
131
      $subForm = new sfForm();
132
 
133
      foreach ($this->getObject()->$relationName as $index => $childObject)
134
      {
135
        $form = $r->newInstanceArgs(array_merge(array($childObject), $formArgs));
136
 
137
        $subForm->embedForm($index, $form, $innerDecorator);
138
        $subForm->getWidgetSchema()->setLabel($index, (string) $childObject);
139
      }
140
 
141
      $this->embedForm($fieldName, $subForm, $decorator);
142
    }
143
  }
144
 
145
  /**
146
   * @see sfFormObject
147
   */
148
  protected function doUpdateObject($values)
149
  {
150
    $this->getObject()->fromArray($values);
151
  }
152
 
153
  /**
154
   * Processes cleaned up values with user defined methods.
155
   *
156
   * To process a value before it is used by the updateObject() method,
157
   * you need to define an updateXXXColumn() method where XXX is the PHP name
158
   * of the column.
159
   *
160
   * The method must return the processed value or false to remove the value
161
   * from the array of cleaned up values.
162
   *
163
   * @see sfFormObject
164
   */
165
  public function processValues($values)
166
  {
167
    // see if the user has overridden some column setter
168
    $valuesToProcess = $values;
169
    foreach ($valuesToProcess as $field => $value)
170
    {
171
      $method = sprintf('update%sColumn', $this->camelize($field));
172
 
173
      if (method_exists($this, $method))
174
      {
175
        if (false === $ret = $this->$method($value))
176
        {
177
          unset($values[$field]);
178
        }
179
        else
180
        {
181
          $values[$field] = $ret;
182
        }
183
      }
184
      else
185
      {
186
        // save files
187
        if ($this->validatorSchema[$field] instanceof sfValidatorFile)
188
        {
189
          $values[$field] = $this->processUploadedFile($field, null, $valuesToProcess);
190
        }
191
      }
192
    }
193
 
194
    return $values;
195
  }
196
 
197
  /**
198
   * Returns true if the current form has some associated i18n objects.
199
   *
200
   * @return Boolean true if the current form has some associated i18n objects, false otherwise
201
   */
202
  public function isI18n()
203
  {
204
    return $this->getObject()->getTable()->hasTemplate('Doctrine_Template_I18n');
205
  }
206
 
207
  /**
208
   * Returns the name of the i18n model.
209
   *
210
   * @return string The name of the i18n model
211
   */
212
  public function getI18nModelName()
213
  {
214
    return $this->getObject()->getTable()->getTemplate('Doctrine_Template_I18n')->getI18n()->getOption('className');
215
  }
216
 
217
  /**
218
   * Returns the name of the i18n form class.
219
   *
220
   * @return string The name of the i18n form class
221
   */
222
  public function getI18nFormClass()
223
  {
224
    return $this->getI18nModelName().'Form';
225
  }
226
 
227
  /**
228
   * Returns the primary key name of the i18n model.
229
   *
230
   * @return string The primary key name of the i18n model
231
   */
232
  public function getI18nModelPrimaryKeyName()
233
  {
234
    $primaryKey = $this->getObject()->getTable()->getIdentifier();
235
 
236
    if (is_array($primaryKey))
237
    {
238
      throw new sfException(sprintf('The model "%s" has composite primary keys and cannot be used with i18n..', $this->getModelName()));
239
    }
240
 
241
    return $primaryKey;
242
  }
243
 
244
  /**
245
   * Returns the i18nField name of the i18n model.
246
   *
247
   * @return string The i18nField name of the i18n model
248
   */
249
  public function getI18nModelI18nField()
250
  {
251
    return $this->getObject()->getTable()->getTemplate('Doctrine_Template_I18n')->getI18n()->getOption('i18nField');
252
  }
253
 
254
  /**
255
   * Updates the default values of the form with the current values of the current object.
256
   */
257
  protected function updateDefaultsFromObject()
258
  {
259
    $defaults = $this->getDefaults();
260
 
261
    // update defaults for the main object
262
    if ($this->isNew())
263
    {
264
      $defaults = $defaults + $this->getObject()->toArray(false);
265
    }
266
    else
267
    {
268
      $defaults = $this->getObject()->toArray(false) + $defaults;
269
    }
270
 
271
    foreach ($this->embeddedForms as $name => $form)
272
    {
273
      if ($form instanceof sfFormDoctrine)
274
      {
275
        $form->updateDefaultsFromObject();
276
        $defaults[$name] = $form->getDefaults();
277
      }
278
    }
279
 
280
    $this->setDefaults($defaults);
281
  }
282
 
283
  /**
284
   * Saves the uploaded file for the given field.
285
   *
286
   * @param  string $field The field name
287
   * @param  string $filename The file name of the file to save
288
   * @param  array  $values An array of values
289
   *
290
   * @return string The filename used to save the file
291
   */
292
  protected function processUploadedFile($field, $filename = null, $values = null)
293
  {
294
    if (!$this->validatorSchema[$field] instanceof sfValidatorFile)
295
    {
296
      throw new LogicException(sprintf('You cannot save the current file for field "%s" as the field is not a file.', $field));
297
    }
298
 
299
    if (null === $values)
300
    {
301
      $values = $this->values;
302
    }
303
 
304
    if (isset($values[$field.'_delete']) && $values[$field.'_delete'])
305
    {
306
      $this->removeFile($field);
307
 
308
      return '';
309
    }
310
 
311
    if (!$values[$field])
312
    {
313
      // this is needed if the form is embedded, in which case
314
      // the parent form has already changed the value of the field
315
      $oldValues = $this->getObject()->getModified(true, false);
316
 
317
      return isset($oldValues[$field]) ? $oldValues[$field] : $this->object->$field;
318
    }
319
 
320
    // we need the base directory
321
    if (!$this->validatorSchema[$field]->getOption('path'))
322
    {
323
      return $values[$field];
324
    }
325
 
326
    $this->removeFile($field);
327
 
328
    return $this->saveFile($field, $filename, $values[$field]);
329
  }
330
 
331
  /**
332
   * Removes the current file for the field.
333
   *
334
   * @param string $field The field name
335
   */
336
  protected function removeFile($field)
337
  {
338
    if (!$this->validatorSchema[$field] instanceof sfValidatorFile)
339
    {
340
      throw new LogicException(sprintf('You cannot remove the current file for field "%s" as the field is not a file.', $field));
341
    }
342
 
343
    $directory = $this->validatorSchema[$field]->getOption('path');
344
    if ($directory && is_file($file = $directory.'/'.$this->getObject()->$field))
345
    {
346
      unlink($file);
347
    }
348
  }
349
 
350
  /**
351
   * Saves the current file for the field.
352
   *
353
   * @param  string          $field    The field name
354
   * @param  string          $filename The file name of the file to save
355
   * @param  sfValidatedFile $file     The validated file to save
356
   *
357
   * @return string The filename used to save the file
358
   */
359
  protected function saveFile($field, $filename = null, sfValidatedFile $file = null)
360
  {
361
    if (!$this->validatorSchema[$field] instanceof sfValidatorFile)
362
    {
363
      throw new LogicException(sprintf('You cannot save the current file for field "%s" as the field is not a file.', $field));
364
    }
365
 
366
    if (null === $file)
367
    {
368
      $file = $this->getValue($field);
369
    }
370
 
371
    $method = sprintf('generate%sFilename', $this->camelize($field));
372
 
373
    if (null !== $filename)
374
    {
375
      return $file->save($filename);
376
    }
377
    else if (method_exists($this, $method))
378
    {
379
      return $file->save($this->$method($file));
380
    }
381
    else if (method_exists($this->getObject(), $method))
382
    {
383
      return $file->save($this->getObject()->$method($file));
384
    }
385
    else if (method_exists($this->getObject(), $method = sprintf('generate%sFilename', $field)))
386
    {
387
      // this non-camelized method name has been deprecated
388
      return $file->save($this->getObject()->$method($file));
389
    }
390
    else
391
    {
392
      return $file->save();
393
    }
394
  }
395
 
396
  /**
397
   * Used in generated forms when models use inheritance.
398
   */
399
  protected function setupInheritance()
400
  {
401
  }
402
 
403
  /**
404
   * Returns the name of the related model.
405
   *
406
   * @param string $alias A relation alias
407
   *
408
   * @return string
409
   *
410
   * @throws InvalidArgumentException If no relation with the supplied alias exists on the current model
411
   */
412
  protected function getRelatedModelName($alias)
413
  {
414
    $table = Doctrine_Core::getTable($this->getModelName());
415
 
416
    if (!$table->hasRelation($alias))
417
    {
418
      throw new InvalidArgumentException(sprintf('The "%s" model has no "%s" relation.', $this->getModelName(), $alias));
419
    }
420
 
421
    $relation = $table->getRelation($alias);
422
 
423
    return $relation['class'];
424
  }
425
}