Development

/branches/1.4/lib/plugins/sfPropelPlugin/lib/validator/sfValidatorPropelUnique.class.php

You must first sign up to be able to contribute.

root/branches/1.4/lib/plugins/sfPropelPlugin/lib/validator/sfValidatorPropelUnique.class.php

Revision 27940, 5.6 kB (checked in by Kris.Wallsmith, 5 years ago)

[1.3, 1.4] fixed field name used when propel unique validator throws a non-global error (closes #8108)

  • Property svn:mime-type set to text/x-php
  • 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  * 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$
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 }
177
Note: See TracBrowser for help on using the browser.