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
 * sfValidatorPropelUnique validates that the uniqueness of a column.
13
 *
14
 * Warning: sfValidatorPropelUnique is susceptible to race conditions.
15
 * To avoid this issue, wrap the validation process and the model saving
16
 * inside a transaction.
17
 *
18
 * @package    symfony
19
 * @subpackage validator
20
 * @author     Fabien Potencier <fabien.potencier@symfony-project.com>
21
 * @version    SVN: $Id: sfValidatorPropelUnique.class.php 27940 2010-02-12 13:31:30Z Kris.Wallsmith $
22
 */
23
class sfValidatorPropelUnique extends sfValidatorSchema
24
{
25
  /**
26
   * Constructor.
27
   *
28
   * @param array  $options   An array of options
29
   * @param array  $messages  An array of error messages
30
   *
31
   * @see sfValidatorSchema
32
   */
33
  public function __construct($options = array(), $messages = array())
34
  {
35
    parent::__construct(null, $options, $messages);
36
  }
37
 
38
  /**
39
   * Configures the current validator.
40
   *
41
   * Available options:
42
   *
43
   *  * model:              The model class (required)
44
   *  * column:             The unique column name in Propel field name format (required)
45
   *                        If the uniqueness is for several columns, you can pass an array of field names
46
   *  * field               Field name used by the form, other than the column name
47
   *  * primary_key:        The primary key column name in Propel field name format (optional, will be introspected if not provided)
48
   *                        You can also pass an array if the table has several primary keys
49
   *  * connection:         The Propel connection to use (null by default)
50
   *  * 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
51
   *
52
   * @see sfValidatorBase
53
   */
54
  protected function configure($options = array(), $messages = array())
55
  {
56
    $this->addRequiredOption('model');
57
    $this->addRequiredOption('column');
58
    $this->addOption('field', null);
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
    if (!is_array($values))
72
    {
73
      throw new InvalidArgumentException('You must pass an array parameter to the clean() method (this validator can only be used as a post validator).');
74
    }
75
 
76
    if (!is_array($this->getOption('column')))
77
    {
78
      $this->setOption('column', array($this->getOption('column')));
79
    }
80
    $columns = $this->getOption('column');
81
 
82
    if (!is_array($field = $this->getOption('field')))
83
    {
84
      $this->setOption('field', $field ? array($field) : array());
85
    }
86
    $fields = $this->getOption('field');
87
 
88
    $criteria = new Criteria();
89
    foreach ($columns as $i => $column)
90
    {
91
      $name = isset($fields[$i]) ? $fields[$i] : $column;
92
      if (!array_key_exists($name, $values))
93
      {
94
        // one of the columns has be removed from the form
95
        return $values;
96
      }
97
 
98
      $colName = call_user_func(array(constant($this->getOption('model').'::PEER'), 'translateFieldName'), $column, BasePeer::TYPE_FIELDNAME, BasePeer::TYPE_COLNAME);
99
 
100
      $criteria->add($colName, $values[$name]);
101
    }
102
 
103
    $object = call_user_func(array(constant($this->getOption('model').'::PEER'), 'doSelectOne'), $criteria, $this->getOption('connection'));
104
 
105
    // if no object or if we're updating the object, it's ok
106
    if (null === $object || $this->isUpdate($object, $values))
107
    {
108
      return $values;
109
    }
110
 
111
    $error = new sfValidatorError($this, 'invalid', array('column' => implode(', ', $this->getOption('column'))));
112
 
113
    if ($this->getOption('throw_global_error'))
114
    {
115
      throw $error;
116
    }
117
 
118
    throw new sfValidatorErrorSchema($this, array(isset($fields[0]) ? $fields[0] : $columns[0] => $error));
119
  }
120
 
121
  /**
122
   * Returns whether the object is being updated.
123
   *
124
   * @param BaseObject  $object   A Propel object
125
   * @param array       $values   An array of values
126
   *
127
   * @return Boolean     true if the object is being updated, false otherwise
128
   */
129
  protected function isUpdate(BaseObject $object, $values)
130
  {
131
    // check each primary key column
132
    foreach ($this->getPrimaryKeys() as $column)
133
    {
134
      $columnPhpName = call_user_func(array(constant($this->getOption('model').'::PEER'), 'translateFieldName'), $column, BasePeer::TYPE_FIELDNAME, BasePeer::TYPE_PHPNAME);
135
      $method = 'get'.$columnPhpName;
136
      if (!isset($values[$column]) or $object->$method() != $values[$column])
137
      {
138
        return false;
139
      }
140
    }
141
 
142
    return true;
143
  }
144
 
145
  /**
146
   * Returns the primary keys for the model.
147
   *
148
   * @return array An array of primary keys
149
   */
150
  protected function getPrimaryKeys()
151
  {
152
    if (null === $this->getOption('primary_key'))
153
    {
154
      $primaryKeys = array();
155
      $tableMap = call_user_func(array(constant($this->getOption('model').'::PEER'), 'getTableMap'));
156
      foreach ($tableMap->getColumns() as $column)
157
      {
158
        if (!$column->isPrimaryKey())
159
        {
160
          continue;
161
        }
162
 
163
        $primaryKeys[] = call_user_func(array(constant($this->getOption('model').'::PEER'), 'translateFieldName'), $column->getPhpName(), BasePeer::TYPE_PHPNAME, BasePeer::TYPE_FIELDNAME);
164
      }
165
 
166
      $this->setOption('primary_key', $primaryKeys);
167
    }
168
 
169
    if (!is_array($this->getOption('primary_key')))
170
    {
171
      $this->setOption('primary_key', array($this->getOption('primary_key')));
172
    }
173
 
174
    return $this->getOption('primary_key');
175
  }
176
}