Browse Source

Update validation generation to be simpler.

Removing the interactive mode makes generating validation rules
simpler.
mark_story 12 years ago
parent
commit
6a801b4503

+ 83 - 186
src/Console/Command/Task/ModelTask.php

@@ -123,6 +123,7 @@ class ModelTask extends BakeTask {
 		$primaryKey = $this->getPrimaryKey($model);
 		$displayField = $this->getDisplayField($model);
 		$fields = $this->getFields($model);
+		$validation = $this->getValidation($model);
 
 		$this->bake($object, false);
 		$this->bakeFixture($model, $useTable);
@@ -359,6 +360,88 @@ class ModelTask extends BakeTask {
 	}
 
 /**
+ * Generate default validation rules.
+ *
+ * @param Cake\ORM\Table $model The model to introspect.
+ * @return array The validation rules.
+ */
+	public function getValidation($model) {
+		if (!empty($this->params['no-validation'])) {
+			return [];
+		}
+		$schema = $model->schema();
+		$fields = $schema->columns();
+		if (empty($fields)) {
+			return false;
+		}
+
+		$skipFields = false;
+		$validate = [];
+		$primaryKey = (array)$schema->primaryKey();
+
+		foreach ($fields as $fieldName) {
+			$field = $schema->column($fieldName);
+			$validation = $this->fieldValidation($fieldName, $field, $primaryKey);
+			if (!empty($validation)) {
+				$validate[$fieldName] = $validation;
+			}
+		}
+		return $validate;
+	}
+
+/**
+ * Does individual field validation handling.
+ *
+ * @param string $fieldName Name of field to be validated.
+ * @param array $metaData metadata for field
+ * @param string $primaryKey
+ * @return array Array of validation for the field.
+ */
+	public function fieldValidation($fieldName, $metaData, $primaryKey) {
+		$ignoreFields = array_merge($primaryKey, ['created', 'modified', 'updated']);
+		if ($metaData['null'] == true && in_array($fieldName, $ignoreFields)) {
+			return false;
+		}
+
+		if ($fieldName === 'email') {
+			$rule = 'email';
+		} elseif ($metaData['type'] === 'uuid') {
+			$rule = 'uuid';
+		} elseif ($metaData['type'] === 'string') {
+			$rule = 'notEmpty';
+		} elseif ($metaData['type'] === 'text') {
+			$rule = 'notEmpty';
+		} elseif ($metaData['type'] === 'integer') {
+			$rule = 'numeric';
+		} elseif ($metaData['type'] === 'float') {
+			$rule = 'numeric';
+		} elseif ($metaData['type'] === 'decimal') {
+			$rule = 'decimal';
+		} elseif ($metaData['type'] === 'boolean') {
+			$rule = 'boolean';
+		} elseif ($metaData['type'] === 'date') {
+			$rule = 'date';
+		} elseif ($metaData['type'] === 'time') {
+			$rule = 'time';
+		} elseif ($metaData['type'] === 'datetime') {
+			$rule = 'datetime';
+		} elseif ($metaData['type'] === 'inet') {
+			$rule = 'ip';
+		}
+
+		$allowEmpty = false;
+		if ($rule !== 'notEmpty' && $metaData['null'] === false) {
+			$allowEmpty = true;
+		}
+
+		return [
+			'rule' => $rule,
+			'allowEmpty' => $allowEmpty,
+		];
+	}
+
+
+/**
  * Generate a key value list of options and a prompt.
  *
  * @param array $options Array of options to use for the selections. indexes must start at 0
@@ -493,192 +576,6 @@ class ModelTask extends BakeTask {
 	}
 
 /**
- * Print out all the associations of a particular type
- *
- * @param string $modelName Name of the model relations belong to.
- * @param string $type Name of association you want to see. i.e. 'belongsTo'
- * @param string $associations Collection of associations.
- * @return void
- */
-	protected function _printAssociation($modelName, $type, $associations) {
-		if (!empty($associations[$type])) {
-			for ($i = 0, $len = count($associations[$type]); $i < $len; $i++) {
-				$out = "\t" . $modelName . ' ' . $type . ' ' . $associations[$type][$i]['alias'];
-				$this->out($out);
-			}
-		}
-	}
-
-/**
- * Handles Generation and user interaction for creating validation.
- *
- * @param Model $model Model to have validations generated for.
- * @return array $validate Array of user selected validations.
- */
-	public function doValidation($model) {
-		if (!$model instanceof Model) {
-			return false;
-		}
-
-		$fields = $model->schema();
-		if (empty($fields)) {
-			return false;
-		}
-
-		$skipFields = false;
-		$validate = array();
-		$this->initValidations();
-		foreach ($fields as $fieldName => $field) {
-			$validation = $this->fieldValidation($fieldName, $field, $model->primaryKey);
-			if (isset($validation['_skipFields'])) {
-				unset($validation['_skipFields']);
-				$skipFields = true;
-			}
-			if (!empty($validation)) {
-				$validate[$fieldName] = $validation;
-			}
-			if ($skipFields) {
-				return $validate;
-			}
-		}
-		return $validate;
-	}
-
-/**
- * Populate the _validations array
- *
- * @return void
- */
-	public function initValidations() {
-		$options = $choices = [];
-		if (class_exists('Cake\Validation\Validation')) {
-			$options = get_class_methods('Cake\Validation\Validation');
-		}
-		sort($options);
-		$default = 1;
-		foreach ($options as $option) {
-			if ($option{0} !== '_') {
-				$choices[$default] = $option;
-				$default++;
-			}
-		}
-		$choices[$default] = 'none'; // Needed since index starts at 1
-		$this->_validations = $choices;
-		return $choices;
-	}
-
-/**
- * Does individual field validation handling.
- *
- * @param string $fieldName Name of field to be validated.
- * @param array $metaData metadata for field
- * @param string $primaryKey
- * @return array Array of validation for the field.
- */
-	public function fieldValidation($fieldName, $metaData, $primaryKey = 'id') {
-		$defaultChoice = count($this->_validations);
-		$validate = $alreadyChosen = [];
-
-		$prompt = __d('cake_console',
-			"or enter in a valid regex validation string.\nAlternatively [s] skip the rest of the fields.\n"
-		);
-		$methods = array_flip($this->_validations);
-
-		$anotherValidator = 'y';
-		while ($anotherValidator === 'y') {
-			if ($this->interactive) {
-				$this->out();
-				$this->out(__d('cake_console', 'Field: <info>%s</info>', $fieldName));
-				$this->out(__d('cake_console', 'Type: <info>%s</info>', $metaData['type']));
-				$this->hr();
-				$this->out(__d('cake_console', 'Please select one of the following validation options:'));
-				$this->hr();
-
-				$optionText = '';
-				for ($i = 1, $m = $defaultChoice / 2; $i <= $m; $i++) {
-					$line = sprintf("%2d. %s", $i, $this->_validations[$i]);
-					$optionText .= $line . str_repeat(" ", 31 - strlen($line));
-					if ($m + $i !== $defaultChoice) {
-						$optionText .= sprintf("%2d. %s\n", $m + $i, $this->_validations[$m + $i]);
-					}
-				}
-				$this->out($optionText);
-				$this->out(__d('cake_console', "%s - Do not do any validation on this field.", $defaultChoice));
-				$this->hr();
-			}
-
-			$guess = $defaultChoice;
-			if ($metaData['null'] != 1 && !in_array($fieldName, [$primaryKey, 'created', 'modified', 'updated'])) {
-				if ($fieldName === 'email') {
-					$guess = $methods['email'];
-				} elseif ($metaData['type'] === 'string' && $metaData['length'] == 36) {
-					$guess = $methods['uuid'];
-				} elseif ($metaData['type'] === 'string') {
-					$guess = $methods['notEmpty'];
-				} elseif ($metaData['type'] === 'text') {
-					$guess = $methods['notEmpty'];
-				} elseif ($metaData['type'] === 'integer') {
-					$guess = $methods['numeric'];
-				} elseif ($metaData['type'] === 'float') {
-					$guess = $methods['numeric'];
-				} elseif ($metaData['type'] === 'boolean') {
-					$guess = $methods['boolean'];
-				} elseif ($metaData['type'] === 'date') {
-					$guess = $methods['date'];
-				} elseif ($metaData['type'] === 'time') {
-					$guess = $methods['time'];
-				} elseif ($metaData['type'] === 'datetime') {
-					$guess = $methods['datetime'];
-				} elseif ($metaData['type'] === 'inet') {
-					$guess = $methods['ip'];
-				}
-			}
-
-			if ($this->interactive === true) {
-				$choice = $this->in($prompt, null, $guess);
-				if ($choice === 's') {
-					$validate['_skipFields'] = true;
-					return $validate;
-				}
-				if (in_array($choice, $alreadyChosen)) {
-					$this->out(__d('cake_console', "You have already chosen that validation rule,\nplease choose again"));
-					continue;
-				}
-				if (!isset($this->_validations[$choice]) && is_numeric($choice)) {
-					$this->out(__d('cake_console', 'Please make a valid selection.'));
-					continue;
-				}
-				$alreadyChosen[] = $choice;
-			} else {
-				$choice = $guess;
-			}
-
-			if (isset($this->_validations[$choice])) {
-				$validatorName = $this->_validations[$choice];
-			} else {
-				$validatorName = Inflector::slug($choice);
-			}
-
-			if ($choice != $defaultChoice) {
-				$validate[$validatorName] = $choice;
-				if (is_numeric($choice) && isset($this->_validations[$choice])) {
-					$validate[$validatorName] = $this->_validations[$choice];
-				}
-			}
-			$anotherValidator = 'n';
-			if ($this->interactive && $choice != $defaultChoice) {
-				$anotherValidator = $this->in(__d('cake_console', "Would you like to add another validation rule\n" .
-					"or skip the rest of the fields?"), array('y', 'n', 's'), 'n');
-				if ($anotherValidator === 's') {
-					$validate['_skipFields'] = true;
-					return $validate;
-				}
-			}
-		}
-		return $validate;
-	}
-
-/**
  * Handles behaviors
  *
  * @param Model $model

+ 1 - 1
tests/Fixture/BakeArticleFixture.php

@@ -34,7 +34,7 @@ class BakeArticleFixture extends TestFixture {
 		'bake_user_id' => ['type' => 'integer', 'null' => false],
 		'title' => ['type' => 'string', 'null' => false],
 		'body' => 'text',
-		'published' => ['type' => 'string', 'length' => 1, 'default' => 'N'],
+		'published' => ['type' => 'boolean', 'length' => 1, 'default' => 0],
 		'created' => 'datetime',
 		'updated' => 'datetime',
 		'_constraints' => ['primary' => ['type' => 'primary', 'columns' => ['id']]]

+ 24 - 4
tests/TestCase/Console/Command/Task/ModelTaskTest.php

@@ -339,13 +339,33 @@ class ModelTaskTest extends TestCase {
 	}
 
 /**
- * test that initializing the validations works.
+ * test getting validation rules with the no-validation rule.
  *
  * @return void
  */
-	public function testInitValidations() {
-		$result = $this->Task->initValidations();
-		$this->assertTrue(in_array('notEmpty', $result));
+	public function testGetValidationDisabled() {
+		$model = TableRegistry::get('BakeArticles');
+		$this->Task->params['no-validation'] = true;
+		$result = $this->Task->getValidation($model);
+		$this->assertEquals([], $result);
+	}
+
+/**
+ * test getting validation rules.
+ *
+ * @return void
+ */
+	public function testGetValidation() {
+		$model = TableRegistry::get('BakeArticles');
+		$result = $this->Task->getValidation($model);
+		$expected = [
+			'id' => ['rule' => 'numeric', 'allowEmpty' => true],
+			'bake_user_id' => ['rule' => 'numeric', 'allowEmpty' => true],
+			'title' => ['rule' => 'notEmpty', 'allowEmpty' => false],
+			'body' => ['rule' => 'notEmpty', 'allowEmpty' => false],
+			'published' => ['rule' => 'boolean', 'allowEmpty' => false],
+		];
+		$this->assertEquals($expected, $result);
 	}
 
 /**