CExistValidator.php 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. <?php
  2. /**
  3. * CExistValidator class file.
  4. *
  5. * @author Qiang Xue <qiang.xue@gmail.com>
  6. * @link http://www.yiiframework.com/
  7. * @copyright 2008-2013 Yii Software LLC
  8. * @license http://www.yiiframework.com/license/
  9. */
  10. /**
  11. * CExistValidator validates that the attribute value exists in a table.
  12. *
  13. * This validator is often used to verify that a foreign key contains a value
  14. * that can be found in the foreign table.
  15. *
  16. * When using the {@link message} property to define a custom error message, the message
  17. * may contain additional placeholders that will be replaced with the actual content. In addition
  18. * to the "{attribute}" placeholder, recognized by all validators (see {@link CValidator}),
  19. * CExistValidator allows for the following placeholders to be specified:
  20. * <ul>
  21. * <li>{value}: replaced with value of the attribute.</li>
  22. * </ul>
  23. *
  24. * @author Qiang Xue <qiang.xue@gmail.com>
  25. * @package system.validators
  26. */
  27. class CExistValidator extends CValidator
  28. {
  29. /**
  30. * @var boolean whether the comparison is case sensitive. Defaults to true.
  31. * Note, by setting it to false, you are assuming the attribute type is string.
  32. */
  33. public $caseSensitive=true;
  34. /**
  35. * @var string the ActiveRecord class name that should be used to
  36. * look for the attribute value being validated. Defaults to null,
  37. * meaning using the ActiveRecord class of the attribute being validated.
  38. * You may use path alias to reference a class name here.
  39. * @see attributeName
  40. */
  41. public $className;
  42. /**
  43. * @var string the ActiveRecord class attribute name that should be
  44. * used to look for the attribute value being validated. Defaults to null,
  45. * meaning using the name of the attribute being validated.
  46. * @see className
  47. */
  48. public $attributeName;
  49. /**
  50. * @var mixed additional query criteria. Either an array or CDbCriteria.
  51. * This will be combined with the condition that checks if the attribute
  52. * value exists in the corresponding table column.
  53. * This array will be used to instantiate a {@link CDbCriteria} object.
  54. */
  55. public $criteria=array();
  56. /**
  57. * @var boolean whether the attribute value can be null or empty. Defaults to true,
  58. * meaning that if the attribute is empty, it is considered valid.
  59. */
  60. public $allowEmpty=true;
  61. /**
  62. * Validates the attribute of the object.
  63. * If there is any error, the error message is added to the object.
  64. * @param CModel $object the object being validated
  65. * @param string $attribute the attribute being validated
  66. * @throws CException if given table does not have specified column name
  67. */
  68. protected function validateAttribute($object,$attribute)
  69. {
  70. $value=$object->$attribute;
  71. if($this->allowEmpty && $this->isEmpty($value))
  72. return;
  73. if(is_array($value))
  74. {
  75. // https://github.com/yiisoft/yii/issues/1955
  76. $this->addError($object,$attribute,Yii::t('yii','{attribute} is invalid.'));
  77. return;
  78. }
  79. $className=$this->className===null?get_class($object):Yii::import($this->className);
  80. $attributeName=$this->attributeName===null?$attribute:$this->attributeName;
  81. $finder=$this->getModel($className);
  82. $table=$finder->getTableSchema();
  83. if(($column=$table->getColumn($attributeName))===null)
  84. throw new CException(Yii::t('yii','Table "{table}" does not have a column named "{column}".',
  85. array('{column}'=>$attributeName,'{table}'=>$table->name)));
  86. $columnName=$column->rawName;
  87. $criteria=new CDbCriteria();
  88. if($this->criteria!==array())
  89. $criteria->mergeWith($this->criteria);
  90. $tableAlias = empty($criteria->alias) ? $finder->getTableAlias(true) : $criteria->alias;
  91. $valueParamName = CDbCriteria::PARAM_PREFIX.CDbCriteria::$paramCount++;
  92. $criteria->addCondition($this->caseSensitive ? "{$tableAlias}.{$columnName}={$valueParamName}" : "LOWER({$tableAlias}.{$columnName})=LOWER({$valueParamName})");
  93. $criteria->params[$valueParamName] = $value;
  94. if(!$finder->exists($criteria))
  95. {
  96. $message=$this->message!==null?$this->message:Yii::t('yii','{attribute} "{value}" is invalid.');
  97. $this->addError($object,$attribute,$message,array('{value}'=>CHtml::encode($value)));
  98. }
  99. }
  100. /**
  101. * Given active record class name returns new model instance.
  102. *
  103. * @param string $className active record class name.
  104. * @return CActiveRecord active record model instance.
  105. *
  106. * @since 1.1.14
  107. */
  108. protected function getModel($className)
  109. {
  110. return CActiveRecord::model($className);
  111. }
  112. }