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
 * sfValidatorDoctrineUnique validates that the uniqueness of a column.
14
 *
15
 * Warning: sfValidatorDoctrineUnique is susceptible to race conditions.
16
 * To avoid this issue, wrap the validation process and the model saving
17
 * inside a transaction.
18
 *
19
 * @package    symfony
20
 * @subpackage doctrine
21
 * @author     Fabien Potencier <fabien.potencier@symfony-project.com>
22
 * @author     Jonathan H. Wage <jonwage@gmail.com>
23
 * @version    SVN: $Id: sfValidatorDoctrineUnique.class.php 23810 2009-11-12 11:07:44Z Kris.Wallsmith $
24
 */
25
class sfValidatorDoctrineUnique extends sfValidatorSchema
26
{
27
  /**
28
   * Constructor.
29
   *
30
   * @param array  An array of options
31
   * @param array  An array of error messages
32
   *
33
   * @see sfValidatorSchema
34
   */
35
  public function __construct($options = array(), $messages = array())
36
  {
37
    parent::__construct(null, $options, $messages);
38
  }
39
 
40
  /**
41
   * Configures the current validator.
42
   *
43
   * Available options:
44
   *
45
   *  * model:              The model class (required)
46
   *  * column:             The unique column name in Doctrine field name format (required)
47
   *                        If the uniquess is for several columns, you can pass an array of field names
48
   *  * primary_key:        The primary key column name in Doctrine field name format (optional, will be introspected if not provided)
49
   *                        You can also pass an array if the table has several primary keys
50
   *  * connection:         The Doctrine connection to use (null by default)
51
   *  * throw_global_error: Whether to throw a global error (false by default) or an error tied to the first field related to the column option array
52
   *
53
   * @see sfValidatorBase
54
   */
55
  protected function configure($options = array(), $messages = array())
56
  {
57
    $this->addRequiredOption('model');
58
    $this->addRequiredOption('column');
59
    $this->addOption('primary_key', null);
60
    $this->addOption('connection', null);
61
    $this->addOption('throw_global_error', false);
62
 
63
    $this->setMessage('invalid', 'An object with the same "%column%" already exist.');
64
  }
65
 
66
  /**
67
   * @see sfValidatorBase
68
   */
69
  protected function doClean($values)
70
  {
71
    $originalValues = $values;
72
    $table = Doctrine_Core::getTable($this->getOption('model'));
73
    if (!is_array($this->getOption('column')))
74
    {
75
      $this->setOption('column', array($this->getOption('column')));
76
    }
77
 
78
    //if $values isn't an array, make it one
79
    if (!is_array($values))
80
    {
81
      //use first column for key
82
      $columns = $this->getOption('column');
83
      $values = array($columns[0] => $values);
84
    }
85
 
86
    $q = Doctrine_Core::getTable($this->getOption('model'))->createQuery('a');
87
    foreach ($this->getOption('column') as $column)
88
    {
89
      $colName = $table->getColumnName($column);
90
      if (!array_key_exists($column, $values))
91
      {
92
        // one of the column has be removed from the form
93
        return $originalValues;
94
      }
95
 
96
      $q->addWhere('a.' . $colName . ' = ?', $values[$column]);
97
    }
98
 
99
    $object = $q->fetchOne();
100
 
101
    // if no object or if we're updating the object, it's ok
102
    if (!$object || $this->isUpdate($object, $values))
103
    {
104
      return $originalValues;
105
    }
106
 
107
    $error = new sfValidatorError($this, 'invalid', array('column' => implode(', ', $this->getOption('column'))));
108
 
109
    if ($this->getOption('throw_global_error'))
110
    {
111
      throw $error;
112
    }
113
 
114
    $columns = $this->getOption('column');
115
 
116
    throw new sfValidatorErrorSchema($this, array($columns[0] => $error));
117
  }
118
 
119
  /**
120
   * Returns whether the object is being updated.
121
   *
122
   * @param BaseObject  A Doctrine object
123
   * @param array       An array of values
124
   *
125
   * @param Boolean     true if the object is being updated, false otherwise
126
   */
127
  protected function isUpdate(Doctrine_Record $object, $values)
128
  {
129
    // check each primary key column
130
    foreach ($this->getPrimaryKeys() as $column)
131
    {
132
      if (!isset($values[$column]) || $object->$column != $values[$column])
133
      {
134
        return false;
135
      }
136
    }
137
 
138
    return true;
139
  }
140
 
141
  /**
142
   * Returns the primary keys for the model.
143
   *
144
   * @return array An array of primary keys
145
   */
146
  protected function getPrimaryKeys()
147
  {
148
    if (null === $this->getOption('primary_key'))
149
    {
150
      $primaryKeys = Doctrine_Core::getTable($this->getOption('model'))->getIdentifier();
151
      $this->setOption('primary_key', $primaryKeys);
152
    }
153
 
154
    if (!is_array($this->getOption('primary_key')))
155
    {
156
      $this->setOption('primary_key', array($this->getOption('primary_key')));
157
    }
158
 
159
    return $this->getOption('primary_key');
160
  }
161
}