/** * @inheritdoc */ public function rules() { return array_merge(parent::rules(), [[['loginModelClass', 'controllerClass', 'viewPath'], 'filter', 'filter' => 'trim'], [['loginModelClass', 'controllerClass', 'viewPath'], 'required'], [['loginModelClass'], 'match', 'pattern' => '/^[\\w\\\\]*$/', 'message' => 'Only word characters and backslashes are allowed.'], [['loginModelClass'], 'validateClass', 'params' => ['extends' => Model::className()]], [['baseControllerClass'], 'validateClass', 'params' => ['extends' => Controller::className()]], [['controllerClass'], 'match', 'pattern' => '/Controller$/', 'message' => 'Controller class name must be suffixed with "Controller".'], [['controllerClass'], 'match', 'pattern' => '/(^|\\\\)[A-Z][^\\\\]+Controller$/', 'message' => 'Controller class name must start with an uppercase letter.'], [['controllerClass'], 'validateNewClass'], [['viewPath'], 'match', 'pattern' => '/^@?\\w+[\\-\\/\\w]*$/', 'message' => 'Only word characters, dashes, slashes and @ are allowed.'], [['viewPath'], 'validatePath'], [['enableI18N'], 'boolean'], [['messageCategory'], 'validateMessageCategory', 'skipOnEmpty' => false]]); }
/** * Initializes CRUD handler * @throws \yii\base\ErrorException */ public function __construct() { $class = $this->modelClass(); if (!is_subclass_of($class, \yii\base\Model::className())) { throw new \yii\base\ErrorException('Invalid model class. Method "getModelClass" has to retrieve Model descendant class.'); } }
/** * @param \yii\base\Model $model * * @return string */ public function getModelDirectory(Model $model) { if (!$model->canGetProperty('idAttribute')) { throw new \LogicException("Model {$model->className()} has not 'idAttribute' property"); } $modelName = $this->getShortClass($model); /** @noinspection PhpUndefinedFieldInspection */ $modelId = $model->{$model->idAttribute}; return $this->_getSubDirectory($modelName, $modelId); }
/** * @inheritdoc */ public function rules() { return array_merge(parent::rules(), [[['modelClass', 'formModelClass', 'baseClass', 'controllerClass', 'baseControllerClass'], 'filter', 'filter' => 'trim'], [['searchModelClass'], 'compare', 'compareAttribute' => 'modelClass', 'operator' => '!==', 'message' => 'Search Model Class must not be equal to Model Class.'], [['baseClass'], 'required'], [['modelClass', 'modelClass', 'controllerClass', 'baseControllerClass', 'searchModelClass'], 'match', 'pattern' => '/^[\\w\\\\]*$/', 'message' => 'Only word characters are allowed.'], [['baseClass'], 'match', 'pattern' => '/^[\\w\\\\]+$/', 'message' => 'Only word characters and backslashes are allowed.'], [['controllerClass', 'searchModelClass'], 'validateNewClass'], [['modelClass', 'formModelClass'], 'validateModelClass', 'skipOnEmpty' => false], [['baseClass', 'modelClass'], 'validateClass', 'params' => ['extends' => Model::className()]], [['baseControllerClass'], 'validateClass', 'params' => ['extends' => Controller::className()]], [['controllerClass'], function ($field) { if ($this->{$field}) { if (!$this->formModelClass) { $this->addError('formModelClass', 'formModelClass required'); } if (!$this->searchModelClass) { $this->addError('searchModelClass', 'searchModelClass required'); } } }]]); }
/** * Creating model using $model configuration property * @return bool true, if model was created, false if it has been already configured as object * @throws \yii\base\InvalidConfigException */ protected function createModel() { if ($this->model instanceof \yii\base\Model) { Yii::info('Model already configured as instanceof ' . $this->model->className(), __METHOD__); return false; } if (is_array($this->model)) { if (!ArrayHelper::isIndexed($this->model) || !$this->model[0] instanceof \yii\base\Model) { throw new InvalidConfigException("Property 'model'" . ' must be configured as indexed array of \\yii\\base\\Model'); } Yii::info('Model property configured as array of ' . $this->model[0]->className(), __METHOD__); return false; } if (is_string($this->model)) { $this->model = Yii::createObject($configuration = ['class' => $this->model]); Yii::info('Model initialized with configuration: ' . VarDumper::dumpAsString($configuration), __METHOD__); } return true; }
/** * @inheritdoc */ public function rules() { return array_merge(parent::rules(), [[['modelClass', 'viewName', 'scenarioName', 'viewPath'], 'filter', 'filter' => 'trim'], [['modelClass', 'viewName', 'viewPath'], 'required'], [['modelClass'], 'match', 'pattern' => '/^[\\w\\\\]*$/', 'message' => 'Only word characters and backslashes are allowed.'], [['modelClass'], 'validateClass', 'params' => ['extends' => Model::className()]], [['viewName'], 'match', 'pattern' => '/^\\w+[\\-\\/\\w]*$/', 'message' => 'Only word characters, dashes and slashes are allowed.'], [['viewPath'], 'match', 'pattern' => '/^@?\\w+[\\-\\/\\w]*$/', 'message' => 'Only word characters, dashes, slashes and @ are allowed.'], [['viewPath'], 'validateViewPath'], [['scenarioName'], 'match', 'pattern' => '/^[\\w\\-]+$/', 'message' => 'Only word characters and dashes are allowed.'], [['enableI18N'], 'boolean'], [['messageCategory'], 'validateMessageCategory', 'skipOnEmpty' => false]]); }
/** * @inheritdoc */ public function validateAttribute($model, $attribute) { if (!$model instanceof ContainerInterface) { throw new InvalidConfigException('Owner model must implement "yii2tech\\embedded\\ContainerInterface" interface.'); } $mapping = $model->getEmbeddedMapping($attribute); if ($this->initializedOnly && !$mapping->getIsValueInitialized()) { return; } $embedded = $model->getEmbedded($attribute); if ($mapping->multiple) { if (!is_array($embedded) && !$embedded instanceof \IteratorAggregate) { $error = $this->message; } else { foreach ($embedded as $embeddedModel) { if (!$embeddedModel instanceof Model) { throw new InvalidConfigException('Embedded object "' . get_class($embeddedModel) . '" must be an instance or descendant of "' . Model::className() . '".'); } if (!$embeddedModel->validate()) { $error = $this->message; } } } } else { if (!$embedded instanceof Model) { throw new InvalidConfigException('Embedded object "' . get_class($embedded) . '" must be an instance or descendant of "' . Model::className() . '".'); } if (!$embedded->validate()) { $error = $this->message; } } if (!empty($error)) { $this->addError($model, $this->addErrorToSource ? $mapping->source : $attribute, $error); } }
public function init() { parent::init(); echo \yii\helpers\Html::hiddenInput("sx-model-value", $this->modelWithProperties->id); echo \yii\helpers\Html::hiddenInput("sx-model", $this->modelWithProperties->className()); }
/** * Returns the JavaScript needed for performing client-side validation. * * @param \yii\base\Model $baseModel the data model being validated * @param string $attribute the name of the attribute to be validated. * @param \yii\web\View $view the view object that is going to be used to render views or view files * containing a model form with this validator applied. * @return string the client-side validation script. Null if the validator does not support * client-side validation. * @see \yii\widgets\ActiveForm::enableClientValidation */ public function clientValidateAttribute($baseModel, $attribute, $view) { $class = $this->baseModel; /** @var ActiveRecord|Model $model */ $model = new $class(); /** @var Validator[] $activeValidators */ $activeValidators = $model->getActiveValidators(); $clientValidators = []; foreach ($activeValidators as $_next) { foreach ($_next->attributes as $_attribute) { if (!(isset($clientValidators[$_attribute]) && is_array($clientValidators[$_attribute]))) { $clientValidators[$_attribute] = []; } $clientValidators[$_attribute][$_next->className()] = new JsExpression('function (attribute, value, messages, options, deffered, $form) {' . preg_replace('/;$/', '', $_next->clientValidateAttribute($model, $attribute, $view)) . '}'); } } $options = ['message' => \Yii::$app->getI18n()->format($this->message, ['attribute' => $model->getAttributeLabel($attribute)], \Yii::$app->language)]; if ($this->skipOnEmpty) { $options['skipOnEmpty'] = 1; } $options['validatorList'] = $clientValidators; $modelName = explode("\\", $baseModel->className()); $options['modelName'] = $modelName[sizeof($modelName) - 1]; $modelName = explode("\\", $this->baseModel); $options['modelBase'] = $modelName[sizeof($modelName) - 1]; $options['attribute'] = $attribute; MultipleModelValidatorAssets::register($view); $str = 'yii.validation.multipleModel(attribute, value, messages, ' . Json::encode($options) . ", deferred, \$form);"; return $str; }
/** * @inheritdoc */ public function rules() { return array_merge(parent::rules(), [[['moduleID', 'controllerID', 'actions', 'formActions', 'baseControllerClass'], 'filter', 'filter' => 'trim'], [['controllerID', 'baseControllerClass'], 'required'], [['controllerID'], 'match', 'pattern' => '/^[a-z][a-z0-9\\-\\/]*$/', 'message' => 'Only a-z, 0-9, dashes (-) and slashes (/) are allowed.'], [['actions', 'formActions'], 'match', 'pattern' => '/^[a-z][a-z0-9\\-,\\s]*$/', 'message' => 'Only a-z, 0-9, dashes (-), spaces and commas are allowed.'], [['baseControllerClass', 'modelClass'], 'match', 'pattern' => '/^[\\w\\\\]*$/', 'message' => 'Only word characters and backslashes are allowed.'], [['baseControllerClass'], 'validateClass', 'params' => ['extends' => Controller::className()]], [['scenarioName'], 'match', 'pattern' => '/^[\\w\\-]+$/', 'message' => 'Only word characters and dashes are allowed.'], [['modelClass'], 'validateClass', 'params' => ['extends' => Model::className()]], [['moduleID'], 'validateModuleID']]); }
public function init() { if (!is_subclass_of($this->modelClass, 'common\\models\\SearchModelInterface') && !is_subclass_of($this->modelClass, Model::className())) { throw new InvalidConfigException("Property 'modelClass': given class must implement 'common\\models\\SearchModelInterface' and extend '" . Model::className() . "'"); } }
/** * @param \yii\base\Model $model */ public function __construct($model) { $this->errors = $model->errors; parent::__construct('Cannot save model ' . $model->className() . ', errors: ' . print_r($this->errors, true)); }
/** * Checks whether the $model exists in the database. * * @param string $targetClass the name of the ActiveRecord class that should be used to validate the uniqueness * of the current attribute value. * @param array $conditions conditions, compatible with [[\yii\db\Query::where()|Query::where()]] key-value format. * @param Model $model the data model to be validated * * @return bool whether the model already exists */ private function modelExists($targetClass, $conditions, $model) { /** @var ActiveRecordInterface $targetClass $query */ $query = $this->prepareQuery($targetClass, $conditions); if (!$model instanceof ActiveRecordInterface || $model->getIsNewRecord() || $model->className() !== $targetClass::className()) { // if current $model isn't in the database yet then it's OK just to call exists() // also there's no need to run check based on primary keys, when $targetClass is not the same as $model's class $exists = $query->exists(); } else { // if current $model is in the database already we can't use exists() /** @var $models ActiveRecordInterface[] */ $models = $query->select($targetClass::primaryKey())->limit(2)->all(); $n = count($models); if ($n === 1) { $keys = array_keys($conditions); $pks = $targetClass::primaryKey(); sort($keys); sort($pks); if ($keys === $pks) { // primary key is modified and not unique $exists = $model->getOldPrimaryKey() != $model->getPrimaryKey(); } else { // non-primary key, need to exclude the current record based on PK $exists = reset($models)->getPrimaryKey() != $model->getOldPrimaryKey(); } } else { $exists = $n > 1; } } return $exists; }
/** * Saves uploaded files. * @param boolean $runValidation whether the validation must be called before saving. * @param array|null $attributeNames list of file attribute names that need to be saved. Defaults to null, * meaning all attributes that are loaded from DB will be saved. * @throws InvalidValueException if the behavior has invalid owner or any file cannot be saved. */ public function saveUploadedFiles($runValidation = true, $attributeNames = null) { if (!($owner = $this->owner) || !$owner instanceof Model) { throw new InvalidValueException(get_class($this) . ' must be attached to an instance of ' . Model::className() . '.'); } if ($runValidation) { $this->validateFileAttributes($attributeNames); } $attributeNames = is_array($attributeNames) ? array_fill_keys($attributeNames, true) : null; foreach ($this->fileAttributes() as $fileAttribute) { if ($attributeNames !== null && !isset($attributeNames[$fileAttribute])) { continue; } $dataAttribute = $this->getFileDataAttribute($fileAttribute); $file = $this->getFileAttribute($fileAttribute); if ($owner->hasErrors($fileAttribute) || $owner->hasErrors($dataAttribute)) { continue; } if ($file->status !== File::STATUS_UPLOADED_FILE) { continue; } if (!$file->save()) { throw new InvalidValueException("Cannot save file '{$file->name}' of the '{$fileAttribute}' attribute."); } } }
/** * Returns a list of fields that can be returned to end users. * * These are the fields that should be returned by default when a user does not explicitly specify which * fields to return for a model. If the user explicitly which fields to return, only the fields declared * in this method can be returned. All other fields will be ignored. * * By default, this method returns [[Model::attributes()]], which are the attributes defined by a model. * * You may override this method to select which fields can be returned or define new fields based * on model attributes. * * The value returned by this method should be an array of field definitions. The array keys * are the field names, and the array values are the corresponding attribute names or callbacks * returning field values. If a field name is the same as the corresponding attribute name, * you can use the field name without a key. * * @return array field name => attribute name or definition */ protected function fields() { if (is_subclass_of($this->modelClass, Model::className())) { /** @var Model $model */ $model = new $this->modelClass(); return $model->attributes(); } else { return array_keys(get_class_vars($this->modelClass)); } }