1<?php 2/** 3 * Zend Framework (http://framework.zend.com/) 4 * 5 * @link http://github.com/zendframework/zf2 for the canonical source repository 6 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 7 * @license http://framework.zend.com/license/new-bsd New BSD License 8 */ 9 10namespace Zend\Validator\Db; 11 12use Traversable; 13use Zend\Db\Adapter\Adapter as DbAdapter; 14use Zend\Db\Sql\Select; 15use Zend\Db\Sql\Sql; 16use Zend\Db\Sql\TableIdentifier; 17use Zend\Stdlib\ArrayUtils; 18use Zend\Validator\AbstractValidator; 19use Zend\Validator\Exception; 20 21/** 22 * Class for Database record validation 23 */ 24abstract class AbstractDb extends AbstractValidator 25{ 26 /** 27 * Error constants 28 */ 29 const ERROR_NO_RECORD_FOUND = 'noRecordFound'; 30 const ERROR_RECORD_FOUND = 'recordFound'; 31 32 /** 33 * @var array Message templates 34 */ 35 protected $messageTemplates = array( 36 self::ERROR_NO_RECORD_FOUND => "No record matching the input was found", 37 self::ERROR_RECORD_FOUND => "A record matching the input was found", 38 ); 39 40 /** 41 * Select object to use. can be set, or will be auto-generated 42 * 43 * @var Select 44 */ 45 protected $select; 46 47 /** 48 * @var string 49 */ 50 protected $schema = null; 51 52 /** 53 * @var string 54 */ 55 protected $table = ''; 56 57 /** 58 * @var string 59 */ 60 protected $field = ''; 61 62 /** 63 * @var mixed 64 */ 65 protected $exclude = null; 66 67 /** 68 * Database adapter to use. If null isValid() will throw an exception 69 * 70 * @var \Zend\Db\Adapter\Adapter 71 */ 72 protected $adapter = null; 73 74 /** 75 * Provides basic configuration for use with Zend\Validator\Db Validators 76 * Setting $exclude allows a single record to be excluded from matching. 77 * Exclude can either be a String containing a where clause, or an array with `field` and `value` keys 78 * to define the where clause added to the sql. 79 * A database adapter may optionally be supplied to avoid using the registered default adapter. 80 * 81 * The following option keys are supported: 82 * 'table' => The database table to validate against 83 * 'schema' => The schema keys 84 * 'field' => The field to check for a match 85 * 'exclude' => An optional where clause or field/value pair to exclude from the query 86 * 'adapter' => An optional database adapter to use 87 * 88 * @param array|Traversable|Select $options Options to use for this validator 89 * @throws \Zend\Validator\Exception\InvalidArgumentException 90 */ 91 public function __construct($options = null) 92 { 93 parent::__construct($options); 94 95 if ($options instanceof Select) { 96 $this->setSelect($options); 97 return; 98 } 99 100 if ($options instanceof Traversable) { 101 $options = ArrayUtils::iteratorToArray($options); 102 } elseif (func_num_args() > 1) { 103 $options = func_get_args(); 104 $firstArgument = array_shift($options); 105 if (is_array($firstArgument)) { 106 $temp = ArrayUtils::iteratorToArray($firstArgument); 107 } else { 108 $temp['table'] = $firstArgument; 109 } 110 111 $temp['field'] = array_shift($options); 112 113 if (!empty($options)) { 114 $temp['exclude'] = array_shift($options); 115 } 116 117 if (!empty($options)) { 118 $temp['adapter'] = array_shift($options); 119 } 120 121 $options = $temp; 122 } 123 124 if (!array_key_exists('table', $options) && !array_key_exists('schema', $options)) { 125 throw new Exception\InvalidArgumentException('Table or Schema option missing!'); 126 } 127 128 if (!array_key_exists('field', $options)) { 129 throw new Exception\InvalidArgumentException('Field option missing!'); 130 } 131 132 if (array_key_exists('adapter', $options)) { 133 $this->setAdapter($options['adapter']); 134 } 135 136 if (array_key_exists('exclude', $options)) { 137 $this->setExclude($options['exclude']); 138 } 139 140 $this->setField($options['field']); 141 if (array_key_exists('table', $options)) { 142 $this->setTable($options['table']); 143 } 144 145 if (array_key_exists('schema', $options)) { 146 $this->setSchema($options['schema']); 147 } 148 } 149 150 /** 151 * Returns the set adapter 152 * 153 * @throws \Zend\Validator\Exception\RuntimeException When no database adapter is defined 154 * @return DbAdapter 155 */ 156 public function getAdapter() 157 { 158 return $this->adapter; 159 } 160 161 /** 162 * Sets a new database adapter 163 * 164 * @param DbAdapter $adapter 165 * @return self Provides a fluent interface 166 */ 167 public function setAdapter(DbAdapter $adapter) 168 { 169 $this->adapter = $adapter; 170 return $this; 171 } 172 173 /** 174 * Returns the set exclude clause 175 * 176 * @return string|array 177 */ 178 public function getExclude() 179 { 180 return $this->exclude; 181 } 182 183 /** 184 * Sets a new exclude clause 185 * 186 * @param string|array $exclude 187 * @return self Provides a fluent interface 188 */ 189 public function setExclude($exclude) 190 { 191 $this->exclude = $exclude; 192 $this->select = null; 193 return $this; 194 } 195 196 /** 197 * Returns the set field 198 * 199 * @return string|array 200 */ 201 public function getField() 202 { 203 return $this->field; 204 } 205 206 /** 207 * Sets a new field 208 * 209 * @param string $field 210 * @return AbstractDb 211 */ 212 public function setField($field) 213 { 214 $this->field = (string) $field; 215 $this->select = null; 216 return $this; 217 } 218 219 /** 220 * Returns the set table 221 * 222 * @return string 223 */ 224 public function getTable() 225 { 226 return $this->table; 227 } 228 229 /** 230 * Sets a new table 231 * 232 * @param string $table 233 * @return self Provides a fluent interface 234 */ 235 public function setTable($table) 236 { 237 $this->table = (string) $table; 238 $this->select = null; 239 return $this; 240 } 241 242 /** 243 * Returns the set schema 244 * 245 * @return string 246 */ 247 public function getSchema() 248 { 249 return $this->schema; 250 } 251 252 /** 253 * Sets a new schema 254 * 255 * @param string $schema 256 * @return self Provides a fluent interface 257 */ 258 public function setSchema($schema) 259 { 260 $this->schema = $schema; 261 $this->select = null; 262 return $this; 263 } 264 265 /** 266 * Sets the select object to be used by the validator 267 * 268 * @param Select $select 269 * @return self Provides a fluent interface 270 */ 271 public function setSelect(Select $select) 272 { 273 $this->select = $select; 274 return $this; 275 } 276 277 /** 278 * Gets the select object to be used by the validator. 279 * If no select object was supplied to the constructor, 280 * then it will auto-generate one from the given table, 281 * schema, field, and adapter options. 282 * 283 * @return Select The Select object which will be used 284 */ 285 public function getSelect() 286 { 287 if ($this->select instanceof Select) { 288 return $this->select; 289 } 290 291 // Build select object 292 $select = new Select(); 293 $tableIdentifier = new TableIdentifier($this->table, $this->schema); 294 $select->from($tableIdentifier)->columns(array($this->field)); 295 $select->where->equalTo($this->field, null); 296 297 if ($this->exclude !== null) { 298 if (is_array($this->exclude)) { 299 $select->where->notEqualTo( 300 $this->exclude['field'], 301 $this->exclude['value'] 302 ); 303 } else { 304 $select->where($this->exclude); 305 } 306 } 307 308 $this->select = $select; 309 310 return $this->select; 311 } 312 313 /** 314 * Run query and returns matches, or null if no matches are found. 315 * 316 * @param string $value 317 * @return array when matches are found. 318 */ 319 protected function query($value) 320 { 321 $sql = new Sql($this->getAdapter()); 322 $select = $this->getSelect(); 323 $statement = $sql->prepareStatementForSqlObject($select); 324 $parameters = $statement->getParameterContainer(); 325 $parameters['where1'] = $value; 326 $result = $statement->execute(); 327 328 return $result->current(); 329 } 330} 331