diff --git a/app/vendor/.gitkeep b/app/vendor/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/app/vendor/autoload.php b/app/vendor/autoload.php new file mode 100644 index 000000000..3e8e561ee --- /dev/null +++ b/app/vendor/autoload.php @@ -0,0 +1,7 @@ + child object id => path where the object first appeared. + * + * @var array> + */ + private $visitedObjects = []; + + /** + * @psalm-readonly + * + * @var bool + */ + public $addTypeHints; + + /** + * @psalm-readonly + * + * @var bool + */ + public $skipDynamicProperties; + + /** + * @psalm-readonly + * + * @var bool + */ + public $inlineNumericScalarArray; + + /** + * @psalm-readonly + * + * @var bool + */ + public $closureSnapshotUses; + + /** + * @psalm-readonly + * + * @var bool + */ + public $trailingCommaInArray; + + /** + * @psalm-readonly + * + * @var int + */ + public $indentLevel; + + /** + * @param int $options + * @param int Indentation level + */ + public function __construct(int $options, int $indentLevel = 0) + { + $this->objectExporters[] = new ObjectExporter\StdClassExporter($this); + + if (! ($options & VarExporter::NO_CLOSURES)) { + $this->objectExporters[] = new ObjectExporter\ClosureExporter($this); + } + + if (! ($options & VarExporter::NO_SET_STATE)) { + $this->objectExporters[] = new ObjectExporter\SetStateExporter($this); + } + + $this->objectExporters[] = new ObjectExporter\InternalClassExporter($this); + + if (! ($options & VarExporter::NO_SERIALIZE)) { + $this->objectExporters[] = new ObjectExporter\SerializeExporter($this); + } + + if (! ($options & VarExporter::NOT_ANY_OBJECT)) { + $this->objectExporters[] = new ObjectExporter\AnyObjectExporter($this); + } + + $this->addTypeHints = (bool) ($options & VarExporter::ADD_TYPE_HINTS); + $this->skipDynamicProperties = (bool) ($options & VarExporter::SKIP_DYNAMIC_PROPERTIES); + $this->inlineNumericScalarArray = (bool) ($options & VarExporter::INLINE_NUMERIC_SCALAR_ARRAY); + $this->closureSnapshotUses = (bool) ($options & VarExporter::CLOSURE_SNAPSHOT_USES); + $this->trailingCommaInArray = (bool) ($options & VarExporter::TRAILING_COMMA_IN_ARRAY); + + $this->indentLevel = $indentLevel; + } + + /** + * @param mixed $var The variable to export. + * @param string[] $path The path to the current variable in the array/object graph. + * @param int[] $parentIds The ids of all objects higher in the graph. + * + * @return string[] The lines of code. + * + * @throws ExportException + */ + public function export($var, array $path, array $parentIds) : array + { + switch ($type = gettype($var)) { + case 'boolean': + case 'integer': + case 'double': + case 'string': + return [var_export($var, true)]; + + case 'NULL': + // lowercase null + return ['null']; + + case 'array': + /** @var array $var */ + return $this->exportArray($var, $path, $parentIds); + + case 'object': + /** @var object $var */ + return $this->exportObject($var, $path, $parentIds); + + default: + // resources + throw new ExportException(sprintf('Type "%s" is not supported.', $type), $path); + } + } + + /** + * @psalm-suppress MixedAssignment + * + * @param array $array The array to export. + * @param string[] $path The path to the current array in the array/object graph. + * @param int[] $parentIds The ids of all objects higher in the graph. + * + * @return string[] The lines of code. + * + * @throws ExportException + */ + public function exportArray(array $array, array $path, array $parentIds) : array + { + if (! $array) { + return ['[]']; + } + + $result = []; + + $count = count($array); + $isNumeric = array_keys($array) === range(0, $count - 1); + + $current = 0; + + $inline = ($this->inlineNumericScalarArray && $isNumeric && $this->isScalarArray($array)); + + foreach ($array as $key => $value) { + $isLast = (++$current === $count); + + $newPath = $path; + $newPath[] = (string) $key; + + $exported = $this->export($value, $newPath, $parentIds); + + if ($inline) { + $result[] = $exported[0]; + } else { + $prepend = ''; + $append = ''; + + if (! $isNumeric) { + $prepend = var_export($key, true) . ' => '; + } + + if (! $isLast || $this->trailingCommaInArray) { + $append = ','; + } + + $exported = $this->wrap($exported, $prepend, $append); + $exported = $this->indent($exported); + + $result = array_merge($result, $exported); + } + } + + if ($inline) { + return ['[' . implode(', ', $result) . ']']; + } + + array_unshift($result, '['); + $result[] = ']'; + + return $result; + } + + /** + * Returns whether the given array only contains scalar values. + * + * Types considered scalar here are int, bool, float, string and null. + * If the array is empty, this method returns true. + * + * @param array $array + * + * @return bool + */ + private function isScalarArray(array $array) : bool + { + foreach ($array as $value) { + if ($value !== null && ! is_scalar($value)) { + return false; + } + } + + return true; + } + + /** + * @param object $object The object to export. + * @param string[] $path The path to the current object in the array/object graph. + * @param int[] $parentIds The ids of all objects higher in the graph. + * + * @return string[] The lines of code. + * + * @throws ExportException + */ + public function exportObject(object $object, array $path, array $parentIds) : array + { + $id = spl_object_id($object); + + foreach ($parentIds as $parentId) { + if (isset($this->visitedObjects[$parentId][$id])) { + throw new ExportException(sprintf( + 'Object of class "%s" has a circular reference at %s. ' . + 'Circular references are currently not supported.', + get_class($object), + ExportException::pathToString($this->visitedObjects[$parentId][$id]) + ), $path); + } + + $this->visitedObjects[$parentId][$id] = $path; + } + + $reflectionObject = new \ReflectionObject($object); + + foreach ($this->objectExporters as $objectExporter) { + if ($objectExporter->supports($reflectionObject)) { + return $objectExporter->export($object, $reflectionObject, $path, $parentIds); + } + } + + // This may only happen when an option is given to disallow specific export methods. + + $className = $reflectionObject->getName(); + + throw new ExportException('Class "' . $className . '" cannot be exported using the current options.', $path); + } + + /** + * Indents every non-empty line. + * + * @param string[] $lines The lines of code. + * + * @return string[] The indented lines of code. + */ + public function indent(array $lines) : array + { + foreach ($lines as & $value) { + if ($value !== '') { + $value = ' ' . $value; + } + } + + return $lines; + } + + /** + * @param string[] $lines The lines of code. + * @param string $prepend The string to prepend to the first line. + * @param string $append The string to append to the last line. + * + * @return string[] + */ + public function wrap(array $lines, string $prepend, string $append) : array + { + $lines[0] = $prepend . $lines[0]; + $lines[count($lines) - 1] .= $append; + + return $lines; + } +} diff --git a/app/vendor/brick/varexporter/src/Internal/ObjectExporter.php b/app/vendor/brick/varexporter/src/Internal/ObjectExporter.php new file mode 100644 index 000000000..9b34614ee --- /dev/null +++ b/app/vendor/brick/varexporter/src/Internal/ObjectExporter.php @@ -0,0 +1,96 @@ +exporter = $exporter; + } + + /** + * Returns whether this exporter supports the given object. + * + * @param \ReflectionObject $reflectionObject A reflection of the object. + * + * @return bool + */ + abstract public function supports(\ReflectionObject $reflectionObject) : bool; + + /** + * Exports the given object. + * + * @param object $object The object to export. + * @param \ReflectionObject $reflectionObject A reflection of the object. + * @param string[] $path The path to the current object in the array/object graph. + * @param int[] $parentIds The ids of all objects higher in the graph. + * + * @return string[] The lines of code. + * + * @throws ExportException + */ + abstract public function export(object $object, \ReflectionObject $reflectionObject, array $path, array $parentIds) : array; + + /** + * Returns the code to create a new object of the given class. + * + * If the class has a constructor, reflection will be used to bypass it. + * + * @param \ReflectionClass $class + * + * @return string[] The lines of code. + */ + final protected function getCreateObjectCode(\ReflectionClass $class) : array + { + $className = '\\' . $class->getName(); + + if ($class->getConstructor() === null) { + return ['$object = new ' . $className . ';']; + } + + $lines = ['$class = new \ReflectionClass(' . $className . '::class);']; + + if ($this->exporter->addTypeHints) { + $lines[] = ''; + $lines[] = '/** @var ' . $className . ' $object */'; + } + + $lines[] = '$object = $class->newInstanceWithoutConstructor();'; + + return $lines; + } + + /** + * Wraps the given PHP code in a static closure. + * + * @param string[] $code The lines of code. + * + * @return string[] The lines of code, wrapped in a closure. + */ + final protected function wrapInClosure(array $code) : array + { + return array_merge( + ['(static function() {'], + $this->exporter->indent($code), + ['})()'] + ); + } +} diff --git a/app/vendor/brick/varexporter/src/Internal/ObjectExporter/AnyObjectExporter.php b/app/vendor/brick/varexporter/src/Internal/ObjectExporter/AnyObjectExporter.php new file mode 100644 index 000000000..5449e71ab --- /dev/null +++ b/app/vendor/brick/varexporter/src/Internal/ObjectExporter/AnyObjectExporter.php @@ -0,0 +1,191 @@ +getCreateObjectCode($reflectionObject); + + $objectAsArray = (array) $object; + + $current = $this->exporter->skipDynamicProperties + ? new \ReflectionClass($object) // properties from class definition only + : $reflectionObject; // properties from class definition + dynamic properties + + $isParentClass = false; + + $returnNewObject = ($reflectionObject->getConstructor() === null); + + while ($current) { + $publicProperties = []; + $nonPublicProperties = []; + $unsetPublicProperties = []; + $unsetNonPublicProperties = []; + + foreach ($current->getProperties() as $property) { + if ($property->isStatic()) { + continue; + } + + if ($isParentClass && ! $property->isPrivate()) { + // property already handled in the child class. + continue; + } + + $name = $property->getName(); + + // getting the property value through the object to array cast, and not through reflection, as this is + // currently the only way to know whether a declared property has been unset - at least before PHP 7.4, + // which will bring ReflectionProperty::isInitialized(). + + $key = $this->getPropertyKey($property); + + if (array_key_exists($key, $objectAsArray)) { + $value = $objectAsArray[$key]; + + if ($property->isPublic()) { + $publicProperties[$name] = $value; + } else { + $nonPublicProperties[$name] = $value; + } + } else { + if ($property->isPublic()) { + $unsetPublicProperties[] = $name; + } else { + $unsetNonPublicProperties[] = $name; + } + } + + $returnNewObject = false; + } + + if ($publicProperties || $unsetPublicProperties) { + $lines[] = ''; + + foreach ($publicProperties as $name => $value) { + /** @psalm-suppress RedundantCast See: https://github.com/vimeo/psalm/issues/4891 */ + $name = (string) $name; + + $newPath = $path; + $newPath[] = $name; + + $newParentIds = $parentIds; + $newParentIds[] = spl_object_id($object); + + $exportedValue = $this->exporter->export($value, $newPath, $newParentIds); + $exportedValue = $this->exporter->wrap($exportedValue, '$object->' . $this->escapePropName($name) . ' = ', ';'); + $lines = array_merge($lines, $exportedValue); + } + + foreach ($unsetPublicProperties as $name) { + $lines[] = 'unset($object->' . $this->escapePropName($name) . ');'; + } + } + + if ($nonPublicProperties || $unsetNonPublicProperties) { + $closureLines = []; + + if ($this->exporter->addTypeHints) { + $closureLines[] = '/** @var \\' . $current->getName() . ' $this */'; + } + + foreach ($nonPublicProperties as $name => $value) { + $newPath = $path; + $newPath[] = $name; + + $newParentIds = $parentIds; + $newParentIds[] = spl_object_id($object); + + $exportedValue = $this->exporter->export($value, $newPath, $newParentIds); + $exportedValue = $this->exporter->wrap($exportedValue, '$this->' . $this->escapePropName($name) . ' = ', ';'); + $closureLines = array_merge($closureLines, $exportedValue); + } + + foreach ($unsetNonPublicProperties as $name) { + $closureLines[] = 'unset($this->' . $this->escapePropName($name) . ');'; + } + + $lines[] = ''; + $lines[] = '(function() {'; + $lines = array_merge($lines, $this->exporter->indent($closureLines)); + $lines[] = '})->bindTo($object, \\' . $current->getName() . '::class)();'; + } + + $current = $current->getParentClass(); + $isParentClass = true; + } + + if ($returnNewObject) { + // no constructor, no properties + return ['new \\' . $reflectionObject->getName()]; + } + + $lines[] = ''; + $lines[] = 'return $object;'; + + return $this->wrapInClosure($lines); + } + + /** + * Returns the key of the given property in the object-to-array cast. + * + * @param \ReflectionProperty $property + * + * @return string + */ + private function getPropertyKey(\ReflectionProperty $property) : string + { + $name = $property->getName(); + + if ($property->isPrivate()) { + return "\0" . $property->getDeclaringClass()->getName() . "\0" . $name; + } + + if ($property->isProtected()) { + return "\0*\0" . $name; + } + + return $name; + } + + /** + * @param string $var + * + * @return string + */ + private function escapePropName(string $var) : string + { + if (preg_match('/^[a-zA-Z_][a-zA-Z0-9_]*$/', $var) === 1) { + return $var; + } + + return '{' . var_export($var, true) . '}'; + } +} diff --git a/app/vendor/brick/varexporter/src/Internal/ObjectExporter/ClosureExporter.php b/app/vendor/brick/varexporter/src/Internal/ObjectExporter/ClosureExporter.php new file mode 100644 index 000000000..6cfb9f57f --- /dev/null +++ b/app/vendor/brick/varexporter/src/Internal/ObjectExporter/ClosureExporter.php @@ -0,0 +1,272 @@ +getName() === \Closure::class; + } + + /** + * {@inheritDoc} + */ + public function export($object, \ReflectionObject $reflectionObject, array $path, array $parentIds) : array + { + assert($object instanceof Closure); + + $reflectionFunction = new \ReflectionFunction($object); + + $file = $reflectionFunction->getFileName(); + $line = $reflectionFunction->getStartLine(); + + $ast = $this->parseFile($file, $path); + $ast = $this->resolveNames($ast); + + $closure = $this->getClosure($reflectionFunction, $ast, $file, $line, $path); + + $prettyPrinter = new ClosureExporter\PrettyPrinter(); + $prettyPrinter->setVarExporterNestingLevel(count($path) + $this->exporter->indentLevel); + + $code = $prettyPrinter->prettyPrintExpr($closure); + + // Consider the pretty-printer output as a single line, to avoid breaking multiline quoted strings and + // heredocs / nowdocs. We must leave the indenting responsibility to the pretty-printer. + + return [$code]; + } + + /** + * @return Parser + */ + private function getParser() + { + if ($this->parser === null) { + $this->parser = (new ParserFactory)->create(ParserFactory::ONLY_PHP7); + } + + return $this->parser; + } + + /** + * Parses the given source file. + * + * @param string $filename The source file name. + * @param string[] $path The path to the closure in the array/object graph. + * + * @return Node\Stmt[] The AST. + * + * @throws ExportException + */ + private function parseFile(string $filename, array $path) : array + { + if (substr($filename, -16) === " : eval()'d code") { + throw new ExportException("Closure defined in eval()'d code cannot be exported.", $path); + } + + $source = @ file_get_contents($filename); + + if ($source === false) { + // @codeCoverageIgnoreStart + throw new ExportException("Cannot open source file \"$filename\" for reading closure code.", $path); + // @codeCoverageIgnoreEnd + } + + try { + $nodes = $this->getParser()->parse($source); + + // throwing error handler + assert($nodes !== null); + + return $nodes; + // @codeCoverageIgnoreStart + } catch (Error $e) { + throw new ExportException("Cannot parse file \"$filename\" for reading closure code.", $path, $e); + // @codeCoverageIgnoreEnd + } + } + + /** + * Resolves namespaced names in the AST. + * + * @param Node[] $ast + * + * @return Node[] + */ + private function resolveNames(array $ast) : array + { + $nameResolver = new NameResolver(); + $nodeTraverser = new NodeTraverser(); + $nodeTraverser->addVisitor($nameResolver); + + return $nodeTraverser->traverse($ast); + } + + /** + * Finds a closure in the source file and returns its node. + * + * @param ReflectionFunction $reflectionFunction Reflection of the closure. + * @param Node[] $ast The AST. + * @param string $file The file name. + * @param int $line The line number where the closure is located in the source file. + * @param string[] $path The path to the closure in the array/object graph. + * + * @return Node\Expr\Closure + * + * @throws ExportException + */ + private function getClosure( + ReflectionFunction $reflectionFunction, + array $ast, + string $file, + int $line, + array $path + ) : Node\Expr\Closure { + $finder = new FindingVisitor(function(Node $node) use ($line) : bool { + return ($node instanceof Node\Expr\Closure || $node instanceof Node\Expr\ArrowFunction) + && $node->getStartLine() === $line; + }); + + $traverser = new NodeTraverser(); + $traverser->addVisitor($finder); + $traverser->traverse($ast); + + $closures = $finder->getFoundNodes(); + $count = count($closures); + + if ($count !== 1) { + throw new ExportException(sprintf( + 'Expected exactly 1 closure in %s on line %d, found %d.', + $file, + $line, + $count + ), $path); + } + + /** @var Node\Expr\Closure|Node\Expr\ArrowFunction $closure */ + $closure = $closures[0]; + + if ($closure instanceof Node\Expr\ArrowFunction) { + $closure = $this->convertArrowFunction($reflectionFunction, $closure); + } + + if ($closure->uses) { + $this->closureHandleUses($reflectionFunction, $closure, $path); + } + + return $closure; + } + + /** + * Convert a parsed arrow function to a closure. + * + * @param ReflectionFunction $reflectionFunction Reflection of the closure. + * @param Node\Expr\ArrowFunction $arrowFunction Parsed arrow function. + * + * @return Node\Expr\Closure + */ + private function convertArrowFunction( + ReflectionFunction $reflectionFunction, + Node\Expr\ArrowFunction $arrowFunction + ) : Node\Expr\Closure { + $closure = new Node\Expr\Closure([], ['arrow_function' => true]); + + $closure->static = false; + $closure->params = $arrowFunction->params; + $closure->returnType = $arrowFunction->returnType; + + $closure->stmts[] = new Node\Stmt\Return_($arrowFunction->expr); + + $static = $reflectionFunction->getStaticVariables(); + + foreach (array_keys($static) as $var) { + assert(is_string($var)); + + $closure->uses[] = new Node\Expr\ClosureUse( + new Node\Expr\Variable($var) + ); + } + + return $closure; + } + + /** + * Handle `use` part of closure. + * + * @param ReflectionFunction $reflectionFunction Reflection of the closure. + * @param Node\Expr\Closure $closure Parsed closure. + * @param string[] $path The path to the closure in the array/object graph. + * + * @throws ExportException + */ + private function closureHandleUses( + ReflectionFunction $reflectionFunction, + Node\Expr\Closure $closure, + array $path + ) : void { + if (! $this->exporter->closureSnapshotUses) { + $message = $closure->hasAttribute('arrow_function') + ? "The arrow function uses variables in the parent scope, this is not supported by default" + : "The closure has bound variables through 'use', this is not supported by default"; + + throw new ExportException("$message. Use the CLOSURE_SNAPSHOT_USE option to export them.", $path); + } + + $static = $reflectionFunction->getStaticVariables(); + $stmts = []; + + $parser = $this->getParser(); + + foreach ($closure->uses as $use) { + $var = $use->var->name; + + assert(is_string($var)); + + $export = array_merge(['exporter->export($static[$var], $path, []), [';']); + $nodes = $parser->parse(implode(PHP_EOL, $export)); + + // throwing error handler + assert($nodes !== null); + + /** @var Node\Stmt\Expression $expr */ + $expr = $nodes[0]; + + $assign = new Node\Expr\Assign( + new Node\Expr\Variable($var), + $expr->expr + ); + $stmts[] = new Node\Stmt\Expression($assign); + } + + $closure->uses = []; + $closure->stmts = array_merge($stmts, $closure->stmts); + } +} diff --git a/app/vendor/brick/varexporter/src/Internal/ObjectExporter/ClosureExporter/PrettyPrinter.php b/app/vendor/brick/varexporter/src/Internal/ObjectExporter/ClosureExporter/PrettyPrinter.php new file mode 100644 index 000000000..4010810a4 --- /dev/null +++ b/app/vendor/brick/varexporter/src/Internal/ObjectExporter/ClosureExporter/PrettyPrinter.php @@ -0,0 +1,41 @@ +varExporterNestingLevel = $level; + } + + /** + * {@inheritDoc} + */ + protected function resetState() : void + { + parent::resetState(); + + $this->indentLevel = 4 * $this->varExporterNestingLevel; + $this->nl = "\n" . str_repeat(' ', $this->indentLevel); + } +} diff --git a/app/vendor/brick/varexporter/src/Internal/ObjectExporter/InternalClassExporter.php b/app/vendor/brick/varexporter/src/Internal/ObjectExporter/InternalClassExporter.php new file mode 100644 index 000000000..1deb23e61 --- /dev/null +++ b/app/vendor/brick/varexporter/src/Internal/ObjectExporter/InternalClassExporter.php @@ -0,0 +1,34 @@ +isInternal(); + } + + /** + * {@inheritDoc} + */ + public function export($object, \ReflectionObject $reflectionObject, array $path, array $parentIds) : array + { + $className = $reflectionObject->getName(); + + throw new ExportException('Class "' . $className . '" is internal, and cannot be exported.', $path); + } +} diff --git a/app/vendor/brick/varexporter/src/Internal/ObjectExporter/SerializeExporter.php b/app/vendor/brick/varexporter/src/Internal/ObjectExporter/SerializeExporter.php new file mode 100644 index 000000000..7c826c3ac --- /dev/null +++ b/app/vendor/brick/varexporter/src/Internal/ObjectExporter/SerializeExporter.php @@ -0,0 +1,50 @@ +hasMethod('__serialize') + && $reflectionObject->hasMethod('__unserialize'); + } + + /** + * {@inheritDoc} + */ + public function export($object, \ReflectionObject $reflectionObject, array $path, array $parentIds) : array + { + $lines = $this->getCreateObjectCode($reflectionObject); + + $lines[] = ''; + + /** + * @psalm-suppress MixedAssignment + * @psalm-suppress MixedMethodCall + */ + $values = $object->__serialize(); + + $exportedValues = $this->exporter->export($values, $path, $parentIds); + $exportedValues = $this->exporter->wrap($exportedValues, '$object->__unserialize(', ');'); + + $lines = array_merge($lines, $exportedValues); + + $lines[] = ''; + $lines[] = 'return $object;'; + + return $this->wrapInClosure($lines); + } +} diff --git a/app/vendor/brick/varexporter/src/Internal/ObjectExporter/SetStateExporter.php b/app/vendor/brick/varexporter/src/Internal/ObjectExporter/SetStateExporter.php new file mode 100644 index 000000000..4963dd260 --- /dev/null +++ b/app/vendor/brick/varexporter/src/Internal/ObjectExporter/SetStateExporter.php @@ -0,0 +1,114 @@ +hasMethod('__set_state')) { + $method = $reflectionObject->getMethod('__set_state'); + + return $method->isPublic() && $method->isStatic(); + } + + return false; + } + + /** + * {@inheritDoc} + */ + public function export($object, \ReflectionObject $reflectionObject, array $path, array $parentIds) : array + { + $className = $reflectionObject->getName(); + + $vars = $this->getObjectVars($object, $path); + + $exportedVars = $this->exporter->exportArray($vars, $path, $parentIds); + $exportedVars = $this->exporter->wrap($exportedVars, '\\' . $className . '::__set_state(', ')'); + + return $exportedVars; + } + + /** + * Returns public and private object properties, as an associative array. + * + * This is unlike get_object_vars(), which only returns properties accessible from the current scope. + * + * The returned values are in line with those returned by var_export() in the array passed to __set_state(); unlike + * var_export() however, this method throws an exception if the object has overridden private properties, as this + * would result in a conflict in array keys. In this case, var_export() would return multiple values in the output, + * which once executed would yield an array containing only the last value for this key in the output. + * + * This way we offer a better safety guarantee, while staying compatible with var_export() in the output. + * + * @psalm-suppress MixedAssignment + * + * @param object $object The object to dump. + * @param string[] $path The path to the object, in the array/object graph. + * + * @return array An associative array of property name to value. + * + * @throws ExportException + */ + private function getObjectVars(object $object, array $path) : array + { + $result = []; + + foreach ((array) $object as $name => $value) { + $name = (string) $name; + $pos = strrpos($name, "\0"); + + if ($pos !== false) { + $name = substr($name, $pos + 1); + } + + assert($name !== false); + + if (array_key_exists($name, $result)) { + $className = get_class($object); + + throw new ExportException( + 'Class "' . $className . '" has overridden private property "' . $name . '". ' . + 'This is not supported for exporting objects with __set_state().', + $path + ); + } + + if ($this->exporter->skipDynamicProperties && $this->isDynamicProperty($object, $name)) { + continue; + } + + $result[$name] = $value; + } + + return $result; + } + + /** + * @param object $object + * @param string $name + * + * @return bool + */ + private function isDynamicProperty(object $object, string $name) : bool + { + $reflectionClass = new \ReflectionClass($object); + $reflectionObject = new \ReflectionObject($object); + + return $reflectionObject->hasProperty($name) && ! $reflectionClass->hasProperty($name); + } +} diff --git a/app/vendor/brick/varexporter/src/Internal/ObjectExporter/StdClassExporter.php b/app/vendor/brick/varexporter/src/Internal/ObjectExporter/StdClassExporter.php new file mode 100644 index 000000000..52fc0a97c --- /dev/null +++ b/app/vendor/brick/varexporter/src/Internal/ObjectExporter/StdClassExporter.php @@ -0,0 +1,35 @@ +getName() === \stdClass::class; + } + + /** + * {@inheritDoc} + */ + public function export($object, \ReflectionObject $reflectionObject, array $path, array $parentIds) : array + { + $exported = $this->exporter->exportArray((array) $object, $path, $parentIds); + + $exported[0] = '(object) ' . $exported[0]; + + return $exported; + } +} diff --git a/app/vendor/brick/varexporter/src/VarExporter.php b/app/vendor/brick/varexporter/src/VarExporter.php new file mode 100644 index 000000000..c2717683f --- /dev/null +++ b/app/vendor/brick/varexporter/src/VarExporter.php @@ -0,0 +1,98 @@ +export($var, [], []); + + if ($indentLevel < 1 || count($lines) < 2) { + $export = implode(PHP_EOL, $lines); + } else { + $firstLine = array_shift($lines); + $lines = array_map(function ($line) use ($indentLevel) { + return str_repeat(' ', $indentLevel) . $line; + }, $lines); + + $export = $firstLine . PHP_EOL . implode(PHP_EOL, $lines); + } + + if ($options & self::ADD_RETURN) { + return 'return ' . $export . ';' . PHP_EOL; + } + + return $export; + } +} diff --git a/app/vendor/cakephp-plugins.php b/app/vendor/cakephp-plugins.php new file mode 100644 index 000000000..114fb5eea --- /dev/null +++ b/app/vendor/cakephp-plugins.php @@ -0,0 +1,11 @@ + [ + 'Bake' => $baseDir . '/vendor/cakephp/bake/', + 'Cake/TwigView' => $baseDir . '/vendor/cakephp/twig-view/', + 'DebugKit' => $baseDir . '/vendor/cakephp/debug_kit/', + 'Migrations' => $baseDir . '/vendor/cakephp/migrations/', + ], +]; diff --git a/app/vendor/cakephp/bake/Dockerfile b/app/vendor/cakephp/bake/Dockerfile new file mode 100644 index 000000000..296613920 --- /dev/null +++ b/app/vendor/cakephp/bake/Dockerfile @@ -0,0 +1,24 @@ +# Basic docker based environment +# Necessary to trick dokku into building the documentation +# using dockerfile instead of herokuish +FROM ubuntu:17.04 + +# Add basic tools +RUN apt-get update && \ + apt-get install -y build-essential \ + software-properties-common \ + curl \ + git \ + libxml2 \ + libffi-dev \ + libssl-dev + +RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php && \ + apt-get update && \ + apt-get install -y php7.2-cli php7.2-mbstring php7.2-xml php7.2-zip php7.2-intl php7.2-opcache php7.2-sqlite + +WORKDIR /code + +VOLUME ["/code"] + +CMD [ '/bin/bash' ] diff --git a/app/vendor/cakephp/bake/LICENSE.txt b/app/vendor/cakephp/bake/LICENSE.txt new file mode 100644 index 000000000..0a0a98c8e --- /dev/null +++ b/app/vendor/cakephp/bake/LICENSE.txt @@ -0,0 +1,28 @@ +The MIT License + +CakePHP(tm) : The Rapid Development PHP Framework (http://cakephp.org) +Copyright (c) 2005-present, Cake Software Foundation, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +Cake Software Foundation, Inc. +1785 E. Sahara Avenue, +Suite 490-204 +Las Vegas, Nevada 89104, +United States of America. diff --git a/app/vendor/cakephp/bake/README.md b/app/vendor/cakephp/bake/README.md new file mode 100644 index 000000000..bd99b84b7 --- /dev/null +++ b/app/vendor/cakephp/bake/README.md @@ -0,0 +1,39 @@ +# Bake plugin for CakePHP + +![Build Status](https://github.com/cakephp/bake/actions/workflows/ci.yml/badge.svg?branch=master) +[![Latest Stable Version](https://img.shields.io/github/v/release/cakephp/bake?sort=semver&style=flat-square)](https://packagist.org/packages/cakephp/bake) +[![Coverage Status](https://img.shields.io/codecov/c/github/cakephp/bake.svg?style=flat-square)](https://codecov.io/github/cakephp/bake) +[![License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE.txt) + +This project provides the code generation functionality for CakePHP. Through a +suite of CLI tools, you can quickly and easily generate code for your application. + +## Installation + +You can install this plugin into your CakePHP application using [composer](http://getcomposer.org). + +The recommended way to install composer packages is: + +``` +composer require --dev cakephp/bake +``` + +## Documentation + +You can find the documentation for bake [on its own cookbook](https://book.cakephp.org/bake/2). + +## Testing + +After installing dependencies with composer you can run tests with `phpunit`: + +```bash +vendor/bin/phpunit +``` + +If your changes require changing the templates that bake uses, you can save time updating tests, by +enabling bake's 'overwrite fixture feature'. This will let you re-generate the expected output files +without having to manually edit each one: + +```bash +UPDATE_TEST_COMPARISON_FILES=1 vendor/bin/phpunit +``` diff --git a/app/vendor/cakephp/bake/composer.json b/app/vendor/cakephp/bake/composer.json new file mode 100644 index 000000000..cd74c330b --- /dev/null +++ b/app/vendor/cakephp/bake/composer.json @@ -0,0 +1,60 @@ +{ + "name": "cakephp/bake", + "description": "Bake plugin for CakePHP", + "type": "cakephp-plugin", + "keywords": ["cakephp", "bake"], + "homepage": "https://github.com/cakephp/bake", + "license": "MIT", + "authors": [ + { + "name": "CakePHP Community", + "homepage": "https://github.com/cakephp/bake/graphs/contributors" + } + ], + "support": { + "issues": "https://github.com/cakephp/bake/issues", + "forum": "https://stackoverflow.com/tags/cakephp", + "irc": "irc://irc.freenode.org/cakephp", + "source": "https://github.com/cakephp/bake" + }, + "require": { + "php": ">=7.2", + "cakephp/cakephp": "^4.1", + "cakephp/twig-view": "^1.0.2", + "brick/varexporter": "^0.3.5" + }, + "require-dev": { + "cakephp/cakephp-codesniffer": "^4.0", + "phpunit/phpunit": "~8.5.0", + "cakephp/debug_kit": "^4.1", + "cakephp/plugin-installer": "^1.3" + }, + "autoload": { + "psr-4": { + "Bake\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "BakeTest\\": "tests/test_app/Plugin/BakeTest/src/", + "Company\\Pastry\\": "tests/test_app/Plugin/Company/Pastry/src/", + "Pastry\\PastryTest\\": "tests/test_app/Plugin/PastryTest/src/", + "WithBakeSubFolder\\": "tests/test_app/Plugin/WithBakeSubFolder/src/", + "Bake\\Test\\": "tests/", + "Bake\\Test\\App\\": "tests/test_app/App/", + "Cake\\Test\\": "vendor/cakephp/cakephp/tests/" + } + }, + "scripts": { + "check": [ + "@test", + "@cs-check" + ], + "cs-check": "phpcs --parallel=16 -p src/ tests/", + "cs-fix": "phpcbf --parallel=16 -p src/ tests/", + "stan": "phpstan analyse src/ && psalm.phar", + "stan-setup": "cp composer.json composer.backup && composer require --dev phpstan/phpstan:0.12.82 psalm/phar:~4.7.0 && mv composer.backup composer.json", + "test": "phpunit", + "test-coverage": "phpunit --coverage-clover=clover.xml" + } +} diff --git a/app/vendor/cakephp/bake/docs.Dockerfile b/app/vendor/cakephp/bake/docs.Dockerfile new file mode 100644 index 000000000..adb6e9447 --- /dev/null +++ b/app/vendor/cakephp/bake/docs.Dockerfile @@ -0,0 +1,18 @@ +# Generate the HTML output. +FROM markstory/cakephp-docs-builder as builder + +# Copy entire repo in with .git so we can build all versions in one image. +COPY docs /data/src + +RUN cd /data/docs-builder \ + && make website LANGS="en es fr ja pt ru" SOURCE=/data/src DEST=/data/website/ + +# Build a small nginx container with just the static site in it. +FROM nginx:1.15-alpine + +COPY --from=builder /data/website /data/website +COPY --from=builder /data/docs-builder/nginx.conf /etc/nginx/conf.d/default.conf + +# Copy docs into place. +RUN cp -R /data/website/html/* /usr/share/nginx/html \ + && rm -rf /data/website diff --git a/app/vendor/cakephp/bake/docs/config/__init__.py b/app/vendor/cakephp/bake/docs/config/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/app/vendor/cakephp/bake/docs/config/all.py b/app/vendor/cakephp/bake/docs/config/all.py new file mode 100644 index 000000000..9e899be5b --- /dev/null +++ b/app/vendor/cakephp/bake/docs/config/all.py @@ -0,0 +1,49 @@ +# Global configuration information used across all the +# translations of documentation. +# +# Import the base theme configuration +from cakephpsphinx.config.all import * + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# + +# The full version, including alpha/beta/rc tags. +release = '2.x' + +# The search index version. +search_version = 'bake-2' + +# The marketing display name for the book. +version_name = '' + +# Project name shown in the black header bar +project = 'CakePHP Bake' + +# Other versions that display in the version picker menu. +version_list = [ + {'name': '1.x', 'number': '/bake/1.x', 'title': '1.x'}, + {'name': '2.x', 'number': '/bake/2.x', 'title': '2.x', 'current': True}, +] + +# Languages available. +languages = ['en', 'es', 'fr', 'ja', 'pt', 'ru'] + +# The GitHub branch name for this version of the docs +# for edit links to point at. +branch = 'master' + +# Current version being built +version = '2.x' + +# Language in use for this directory. +language = 'en' + +show_root_link = True + +repository = 'cakephp/bake' + +source_path = 'docs/' + +hide_page_contents = ('search', '404', 'contents') diff --git a/app/vendor/cakephp/bake/docs/en/conf.py b/app/vendor/cakephp/bake/docs/en/conf.py new file mode 100644 index 000000000..f638bda22 --- /dev/null +++ b/app/vendor/cakephp/bake/docs/en/conf.py @@ -0,0 +1,9 @@ +import sys, os + +# Append the top level directory of the docs, so we can import from the config dir. +sys.path.insert(0, os.path.abspath('..')) + +# Pull in all the configuration options defined in the global config file.. +from config.all import * + +language = 'en' diff --git a/app/vendor/cakephp/bake/docs/en/contents.rst b/app/vendor/cakephp/bake/docs/en/contents.rst new file mode 100644 index 000000000..08c3e957c --- /dev/null +++ b/app/vendor/cakephp/bake/docs/en/contents.rst @@ -0,0 +1,7 @@ +.. toctree:: + :maxdepth: 2 + :caption: CakePHP Bake + + /index + /usage + /development diff --git a/app/vendor/cakephp/bake/docs/en/development.rst b/app/vendor/cakephp/bake/docs/en/development.rst new file mode 100644 index 000000000..e1c1aa7bf --- /dev/null +++ b/app/vendor/cakephp/bake/docs/en/development.rst @@ -0,0 +1,348 @@ +Extending Bake +############## + +Bake features an extensible architecture that allows your application or plugins +to modify or add-to the base functionality. Bake makes use of a dedicated +view class which uses the `Twig `_ template engine. + +Bake Events +=========== + +As a view class, ``BakeView`` emits the same events as any other view class, +plus one extra initialize event. However, whereas standard view classes use the +event prefix "View.", ``BakeView`` uses the event prefix "Bake.". + +The initialize event can be used to make changes which apply to all baked +output, for example to add another helper to the bake view class this event can +be used:: + + on('Bake.initialize', function (EventInterface $event) { + $view = $event->getSubject(); + + // In my bake templates, allow the use of the MySpecial helper + $view->loadHelper('MySpecial', ['some' => 'config']); + + // And add an $author variable so it's always available + $view->set('author', 'Andy'); + }); + +Bake events can be handy for making small changes to existing templates. +For example, to change the variable names used when baking controller/template +files one can use a function listening for ``Bake.beforeRender`` to modify the +variables used in the bake templates:: + + on('Bake.beforeRender', function (EventInterface $event) { + $view = $event->getSubject(); + + // Use $rows for the main data variable in indexes + if ($view->get('pluralName')) { + $view->set('pluralName', 'rows'); + } + if ($view->get('pluralVar')) { + $view->set('pluralVar', 'rows'); + } + + // Use $theOne for the main data variable in view/edit + if ($view->get('singularName')) { + $view->set('singularName', 'theOne'); + } + if ($view->get('singularVar')) { + $view->set('singularVar', 'theOne'); + } + }); + +You may also scope the ``Bake.beforeRender`` and ``Bake.afterRender`` events to +a specific generated file. For instance, if you want to add specific actions to +your UsersController when generating from a **Controller/controller.twig** file, +you can use the following event:: + + on( + 'Bake.beforeRender.Controller.controller', + function (EventInterface $event) { + $view = $event->getSubject(); + if ($view->get('name') === 'Users') { + // add the login and logout actions to the Users controller + $view->set('actions', [ + 'login', + 'logout', + 'index', + 'view', + 'add', + 'edit', + 'delete' + ]); + } + } + ); + +By scoping event listeners to specific bake templates, you can simplify your +bake related event logic and provide callbacks that are easier to test. + +Bake Template Syntax +==================== + +Bake template files use the `Twig `__ template syntax. + +One way to see/understand how bake templates works, especially when attempting +to modify bake template files, is to bake a class and compare the template used +with the pre-processed template file which is left in the application's +**tmp/bake** folder. + +So, for example, when baking a command like so: + +.. code-block:: bash + + bin/cake bake command Foo + +The template used (**vendor/cakephp/bake/templates/bake/Command/command.twig**) +looks like this:: + + Test->classSuffixes[$this->name()])) { + $this->Test->classSuffixes[$this->name()] = 'Foo'; + } + + $name = ucfirst($this->name()); + if (!isset($this->Test->classTypes[$name])) { + $this->Test->classTypes[$name] = 'Foo'; + } + + return parent::bakeTest($className); + } + +* The **class suffix** will be appened to the name provided in your ``bake`` + call. In the previous example, it would create a ``ExampleFooTest.php`` file. +* The **class type** will be the sub-namespace used that will lead to your + file (relative to the app or the plugin you are baking into). In the previous + example, it would create your test with the namespace ``App\Test\TestCase\Foo``. + +Configuring the BakeView class +============================== + +The bake commands use the ``BakeView`` class to render the templates. You can +access the instance by listening to the ``Bake.initialize`` event. For example, here's +how you can load your own helper so that it can be used in bake templates:: + + on( + 'Bake.initialize', + function ($event, $view) { + $view->loadHelper('Foo'); + } + ); + +.. meta:: + :title lang=en: Extending Bake + :keywords lang=en: command line interface, development, bake view, bake template syntax, twig, erb tags, percent tags diff --git a/app/vendor/cakephp/bake/docs/en/index.rst b/app/vendor/cakephp/bake/docs/en/index.rst new file mode 100644 index 000000000..28899b7b0 --- /dev/null +++ b/app/vendor/cakephp/bake/docs/en/index.rst @@ -0,0 +1,28 @@ +Bake Console +############ + +CakePHP's bake console is another effort to get you up and running in CakePHP +– fast. The bake console can create any of CakePHP's basic ingredients: models, +behaviors, views, helpers, controllers, components, test cases, fixtures and plugins. +And we aren't just talking skeleton classes: Bake can create a fully functional +application in just a few minutes. In fact, Bake is a natural step to take once +an application has been scaffolded. + +Installation +============ + +Before trying to use or extend bake, make sure it is installed in your +application. Bake is provided as a plugin that you can install with Composer:: + + composer require --dev cakephp/bake:"^2.0" + +The above will install bake as a development dependency. This means that it will +not be installed when you do production deployments. + +When using the Twig templates make sure you are loading the +``Cake/TwigView`` plugin with its bootstrap. You can also omit it +completely which then makes Bake plugin load this plugin on demand. + +.. meta:: + :title lang=en: Bake Console + :keywords lang=en: command line interface,development,bake view, bake template syntax,erb tags,asp tags,percent tags diff --git a/app/vendor/cakephp/bake/docs/en/usage.rst b/app/vendor/cakephp/bake/docs/en/usage.rst new file mode 100644 index 000000000..d68a745f0 --- /dev/null +++ b/app/vendor/cakephp/bake/docs/en/usage.rst @@ -0,0 +1,62 @@ +Code Generation with Bake +######################### + +The Bake console is run using the PHP CLI (command line interface). +If you have problems running the script, ensure that: + +#. You have the PHP CLI installed and that it has the proper modules enabled + (eg: MySQL, intl). +#. Users also might have issues if the database host is 'localhost' and should + try '127.0.0.1' instead, as localhost can cause issues with PHP CLI. +#. Depending on how your computer is configured, you may have to set execute + rights on the cake bash script to call it using ``bin/cake bake``. + +Before running bake you should make sure you have at least one database +connection configured. + +You can get the list of available bake command by running ``bin/cake bake --help`` +(For Windows usage ``bin\cake bake --help``) :: + + $ bin/cake bake --help + Current Paths: + + * app: src/ + * root: /path/to/your/app/ + * core: /path/to/your/app/vendor/cakephp/cakephp/ + + Available Commands: + + Bake: + - bake all + - bake behavior + - bake cell + - bake command + - bake component + - bake controller + - bake controller all + - bake fixture + - bake fixture all + - bake form + - bake helper + - bake mailer + - bake middleware + - bake model + - bake model all + - bake plugin + - bake template + - bake template all + - bake test + + To run a command, type `cake command_name [args|options]` + To get help on a specific command, type `cake command_name --help` + +Bake Themes +=========== + +The theme option is common to all bake commands, and allows changing the bake +template files used when baking. To create your own templates, see the +:ref:`bake theme creation documentation `. + +.. meta:: + :title lang=en: Code Generation with Bake + :keywords lang=en: command line interface,functional application,database,database configuration,bash script,basic ingredients,project,model,path path,code generation,scaffolding,windows users,configuration file,few minutes,config,iew,shell,models,running,mysql diff --git a/app/vendor/cakephp/bake/docs/es/conf.py b/app/vendor/cakephp/bake/docs/es/conf.py new file mode 100644 index 000000000..4691ece6a --- /dev/null +++ b/app/vendor/cakephp/bake/docs/es/conf.py @@ -0,0 +1,9 @@ +import sys, os + +# Append the top level directory of the docs, so we can import from the config dir. +sys.path.insert(0, os.path.abspath('..')) + +# Pull in all the configuration options defined in the global config file.. +from config.all import * + +language = 'es' diff --git a/app/vendor/cakephp/bake/docs/es/contents.rst b/app/vendor/cakephp/bake/docs/es/contents.rst new file mode 100644 index 000000000..08c3e957c --- /dev/null +++ b/app/vendor/cakephp/bake/docs/es/contents.rst @@ -0,0 +1,7 @@ +.. toctree:: + :maxdepth: 2 + :caption: CakePHP Bake + + /index + /usage + /development diff --git a/app/vendor/cakephp/bake/docs/es/development.rst b/app/vendor/cakephp/bake/docs/es/development.rst new file mode 100644 index 000000000..7f717d051 --- /dev/null +++ b/app/vendor/cakephp/bake/docs/es/development.rst @@ -0,0 +1,17 @@ +Extending Bake +############## + +.. note:: + La documentación no es compatible actualmente con el idioma espaƱol en esta pĆ”gina. + + Por favor, siĆ©ntase libre de enviarnos un pull request en + `Github `_ o utilizar el botón **Improve this Doc** para proponer directamente los cambios. + + Usted puede hacer referencia a la versión en InglĆ©s en el menĆŗ de selección superior + para obtener información sobre el tema de esta pĆ”gina. + +.. _creating-a-bake-theme: + +.. meta:: + :title lang=es: Extending Bake + :keywords lang=es: command line interface,development,bake view, bake template syntax,erb tags,asp tags,percent tags diff --git a/app/vendor/cakephp/bake/docs/es/index.rst b/app/vendor/cakephp/bake/docs/es/index.rst new file mode 100644 index 000000000..80f1fa654 --- /dev/null +++ b/app/vendor/cakephp/bake/docs/es/index.rst @@ -0,0 +1,31 @@ +Consola bake +############ + +La consola bake de CakePHP es otro esfuerzo para preparar y ejecutar CakePHP rĆ”pidamente. + +La consola bake puede crear cualquiera de los ingredientes bĆ”sicos de CakePHP: +modelos, behaviours, vistas, helpers, controladores, componentes, casos de +prueba, fixtures y plugins. + +Y no hablamos sólo de esqueletos de clases: Bake puede crear una aplicación +totalmente funcional en solo un par de minutos. + +De hecho, Bake es un paso natural a dar una vez ha sido creado el esqueleto de +la aplicación. + +Instalación +=========== + +Antes de intentar utilizar o extender bake asegĆŗrate de que estĆ” instalado en tu +aplicación. + +Bake estĆ” incluido como un plugin que puedes instalar con Composer:: + + composer require --dev cakephp/bake:~1.0 + +La instrucción anterior instalarĆ” bake como una dependencia de desarrollo. Esto +significa que no serĆ” instalado cuando hagas despliegues en producción. + +.. meta:: + :title lang=es: Consola Bake + :keywords lang=es: interfaz de lĆ­nea de comando,desarrollo,bake vista, bake sintaxis plantilla,erb tags,asp tags,percent tags diff --git a/app/vendor/cakephp/bake/docs/es/usage.rst b/app/vendor/cakephp/bake/docs/es/usage.rst new file mode 100644 index 000000000..dad6ffd95 --- /dev/null +++ b/app/vendor/cakephp/bake/docs/es/usage.rst @@ -0,0 +1,115 @@ +Crear código con Bake +##################### + +La consola de CAKE se ejecuta usando PHP CLI (command line interface). +Si tiene problemas para ejecutar el script, asegurese de: + +#. Tener instalado el PHP CLI y que estĆ©n los módulos correspondientes + habilitados (ej: MySQL y intl). +#. Si el host de base de datos es 'localhost', intente realizar la conexión con + el ip '127.0.0.1'. En algunos casos PHP CLI tiene problemas al referenciar + por nombre de host (localhost). +#. Dependiendo de como estĆ© configurado su equipo, la ejecución del comando + CAKE BAKE (cake bash script) puede requerir permisos de ejecución al + lanzar ``bin/cake bake``. + +Antes de comenzar la ejecución, asegĆŗrese de disponer al menos de una conexión +a una base de datos configurada. + +Para comenzar con la ejecución del comando debe abrir la consola de windows +y ejecutar "Cake Bake" + +#. Ir a Inicio (Start) > Ejecutar (Run) +#. Escribir "cmd" y presionar 'Enter' +#. Navegar hasta llegar a la carpeta de instalación de cake +#. Acceder a la carpeta 'bin' +#. Escribir 'Cake bake' lo cual deberĆ” devolver un listado con todas las + tareas/actividades disponibles. + +El resultado deberĆ­a ser algo similar a lo siguiente:: + + $ bin/cake bake + + Welcome to CakePHP v3.1.6 Console + --------------------------------------------------------------- + App : src + Path: /var/www/cakephp.dev/src/ + PHP: 5.5.8 + --------------------------------------------------------------- + The following commands can be used to generate skeleton code for your application. + + Available bake commands: + + - all + - behavior + - cell + - component + - controller + - fixture + - form + - helper + - mailer + - migration + - migration_snapshot + - model + - plugin + - shell + - shell-helper + - template + - test + + By using 'cake bake [name]' you can invoke a specific bake task. + +Puede obtener mĆ”s información sobre lo que realiza cada una de las actividades +y sus opciones usando el parametro '--help' option:: + + $ bin/cake bake controller --help + + Welcome to CakePHP v3.1.6 Console + --------------------------------------------------------------- + App : src + Path: /var/www/cakephp.dev/src/ + --------------------------------------------------------------- + Bake a controller skeleton. + + Usage: + cake bake controller [subcommand] [options] [] + + Subcommands: + + all Bake all controllers with CRUD methods. + + To see help on a subcommand use `cake bake controller [subcommand] --help` + + Options: + + --help, -h Display this help. + --verbose, -v Enable verbose output. + --quiet, -q Enable quiet output. + --plugin, -p Plugin to bake into. + --force, -f Force overwriting existing files without prompting. + --connection, -c The datasource connection to get data from. + (default: default) + --theme, -t The theme to use when baking code. + --components The comma separated list of components to use. + --helpers The comma separated list of helpers to use. + --prefix The namespace/routing prefix to use. + --no-test Do not generate a test skeleton. + --no-actions Do not generate basic CRUD action methods. + + Arguments: + + name Name of the controller to bake. Can use Plugin.name to bake + controllers into plugins. (optional) + +Temas Bake / Templates +====================== + +La opción ``theme`` es genĆ©rica para todos los comandos bake y permite cambiar los +templates de bake utilizados para generar los archivos finales. Para crear sus +propios templates, ver :ref:`bake theme creation documentation +`. + +.. meta:: + :title lang=es: Crear código con Bake + :keywords lang=es: interfaz de lĆ­nea de comando, aplicación funcional, base de datos, configuración de base de datos, bash script, ingredientes bĆ”sicos, proyecto, modelo, path, crear código, generación de código, scaffolding, usuarios windows, archivo de configuración, pocos minutos, configurar, iew, shell, modelos, running, mysql diff --git a/app/vendor/cakephp/bake/docs/fr/conf.py b/app/vendor/cakephp/bake/docs/fr/conf.py new file mode 100644 index 000000000..b02032efa --- /dev/null +++ b/app/vendor/cakephp/bake/docs/fr/conf.py @@ -0,0 +1,9 @@ +import sys, os + +# Append the top level directory of the docs, so we can import from the config dir. +sys.path.insert(0, os.path.abspath('..')) + +# Pull in all the configuration options defined in the global config file.. +from config.all import * + +language = 'fr' diff --git a/app/vendor/cakephp/bake/docs/fr/contents.rst b/app/vendor/cakephp/bake/docs/fr/contents.rst new file mode 100644 index 000000000..08c3e957c --- /dev/null +++ b/app/vendor/cakephp/bake/docs/fr/contents.rst @@ -0,0 +1,7 @@ +.. toctree:: + :maxdepth: 2 + :caption: CakePHP Bake + + /index + /usage + /development diff --git a/app/vendor/cakephp/bake/docs/fr/development.rst b/app/vendor/cakephp/bake/docs/fr/development.rst new file mode 100644 index 000000000..61de705da --- /dev/null +++ b/app/vendor/cakephp/bake/docs/fr/development.rst @@ -0,0 +1,351 @@ +Etendre Bake +############ + +Bake dispose d'une architecture extensible qui permet Ć  votre application ou +Ć  vos plugins de modifier ou ajouter la fonctionnalitĆ© de base. Bake utilise une +classe de vue dĆ©diĆ©e qui n'utilise pas la syntaxe PHP standard. + +Events de Bake +============== + +Comme une classe de vue, ``BakeView`` envoie les mĆŖmes events que toute autre +classe de vue, ainsi qu'un event initialize supplĆ©mentaire. Cependant, +alors que les classes de vue standard utilisent le prĆ©fixe d'event +"View.", ``BakeView`` utilise le prĆ©fixe d'event "Bake.". + +L'event initialize peut ĆŖtre utilisĆ© pour faire des changements qui +s'appliquent Ć  toutes les sorties fabriquĆ©es avec bake, par exemple pour ajouter +un autre helper Ć  la classe de vue bake, cet event peut ĆŖtre utilisĆ©:: + + on('Bake.initialize', function (Event $event) { + $view = $event->getSubject(); + + // Dans mes templates de bake, permet l'utilisation du helper MySpecial + $view->loadHelper('MySpecial', ['some' => 'config']); + + // Et ajoute une variable $author pour qu'elle soit toujours disponible + $view->set('author', 'Andy'); + + }); + +Si vous souhaitez modifier bake Ć  partir d'un autre plugin, mettre les events +de bake de votre plugin dans le fichier ``config/bootstrap.php`` du plugin est +une bonne idĆ©e. + +Les events de bake peuvent ĆŖtre pratiques pour faire de petits changements dans +les templates existants. Par exemple, pour changer les noms de variables +utilisĆ©s lors de la crĆ©ation avec bake de fichiers de controller/template, on +pourra utiliser une fonction qui Ć©coute ``Bake.beforeRender`` pour modifier les +variables utilisĆ©es dans les templates de bake:: + + on('Bake.beforeRender', function (Event $event) { + $view = $event->getSubject(); + + // Utilise $rows pour les principales variables de donnĆ©es dans les indexes + if ($view->get('pluralName')) { + $view->set('pluralName', 'rows'); + } + if ($view->get('pluralVar')) { + $view->set('pluralVar', 'rows'); + } + + // Utilise $theOne pour les principales variable de donnĆ©es dans les view/edit + if ($view->get('singularName')) { + $view->set('singularName', 'theOne'); + } + if ($view->get('singularVar')) { + $view->set('singularVar', 'theOne'); + } + + }); + +Vous pouvez aussi scoper les events ``Bake.beforeRender`` et +``Bake.afterRender`` dans un fichier gĆ©nĆ©rĆ© spĆ©cifique. Par exemple, si vous +souhaitez ajouter des actions spĆ©cifiques Ć  votre UsersController quand vous le +gĆ©nĆ©rez Ć  partir d'un fichier **Controller/controller.ctp**, vous pouvez +utiliser l'event suivant:: + + on( + 'Bake.beforeRender.Controller.controller', + function (Event $event) { + $view = $event->subject; + if ($view->viewVars['name'] == 'Users') { + // ajouter les actions login et logout au controller Users + $view->viewVars['actions'] = [ + 'login', + 'logout', + 'index', + 'view', + 'add', + 'edit', + 'delete' + ]; + } + } + ); + +En scopant les Ć©couteurs d'event vers des templates de bake spĆ©cifiques, vous +pouvez simplifier votre logique d'event liĆ©e Ć  bake et fournir des callbacks +qui sont plus faciles Ć  tester. + +Syntaxe de Template de Bake +=========================== + +Les fichiers de template de Bake utilisent les balises erb-style (``<% %>``) +pour indiquer la logique des templates, et traitent le reste, y compris les +balises php, comme du texte. + +.. note:: + + Les fichiers de template de Bake n'utilisent pas, et sont insensibles aux + ``asp_tags`` de la configuration de php ini. + +``BakeView`` intĆØgre les balises suivantes: + + * ``<%`` Une balise php ouverte de template de Bake + * ``%>`` Une balise php fermante de template de Bake + * ``<%=`` Une balise php de short-echo de template de Bake + * ``<%-`` Une balise php ouverte de template de Bake, enlevant tout espace + en tĆŖte avant la balise + * ``-%>`` Une balise php fermante de template de Bake, enlevant les espaces + Ć  a fin aprĆØs la balise + +Une faƧon de voir/comprendre la faƧon dont les templates de Bake fonctionne, +spĆ©cialement quand on essaie de modifier les fichiers de template de bake, est +de crĆ©er avec bake une classe et de comparer le template utilisĆ© avec le +template dĆ©jĆ  prĆ©sent dans le dossier **tmp/bake** de votre application. + +Ainsi, par exemple, pour crĆ©er avec bake un shell comme ceci: + +.. code-block:: bash + + bin/cake bake shell Foo + +Le template utilisĆ© +(**vendor/cakephp/cakephp/src/Template/Bake/Shell/shell.ctp**) +ressemble Ć  ceci:: + + \Shell; + + use Cake\Console\Shell; + + /** + * <%= $name %> shell command. + */ + class <%= $name %>Shell extends Shell + { + + /** + * main() method. + * + * @return bool|int Success or error code. + */ + public function main() + { + } + + } + +Le fichier template dĆ©jĆ  prĆ©sent (pre-processed) +(**tmp/bake/Bake-Shell-shell-ctp.php**), qui est le fichier rĆ©ellement +rendu, ressemble Ć  ceci:: + + \Shell; + + use Cake\Console\Shell; + + /** + * shell command. + */ + class Shell extends Shell + { + + /** + * main() method. + * + * @return bool|int Success or error code. + */ + public function main() + { + } + + } + +Et la classe rĆ©sultante construite avec bake (**src/Shell/FooShell.php**) +ressemble Ć  ceci:: + + \Foo; + + /** + * <%= $name %> foo + */ + class <%= $name %>Foo + { + // Add code. + } + +Vous devriez maintenant voir votre nouvelle tĆ¢che dans l'affichage de +``bin/cake bake``. Vous pouvez lancer votre nouvelle tĆ¢che en exĆ©cutant +``bin/cake bake foo Example``. +Cela va gĆ©nĆ©rer une nouvelle classe ``ExampleFoo`` dans +**src/Foo/ExampleFoo.php** que votre application va +pouvoir utiliser. + +Si vous souhaitez que votre appel Ć  ``bake`` crĆ©e Ć©galement un fichier de test +pour la classe ``ExampleFoo``, vous devrez surcharger la mĆ©thode ``bakeTest()`` +dans la classe ``FooTask`` pour y dĆ©finir le suffixe et le namespace de la +classe de votre nom de commande personnalisĆ©e:: + + public function bakeTest($className) + { + if (!isset($this->Test->classSuffixes[$this->name()])) { + $this->Test->classSuffixes[$this->name()] = 'Foo'; + } + + $name = ucfirst($this->name()); + if (!isset($this->Test->classTypes[$name])) { + $this->Test->classTypes[$name] = 'Foo'; + } + + return parent::bakeTest($className); + } + +* Le **suffixe de classe** sera ajoutĆ© aprĆØs le nom passĆ© Ć  ``bake``. Dans le + cadre de l'exemple ci-dessus, cela crĆ©erait un fichier ``ExampleFooTest.php``. +* Le **type de classe** sera le sous-namespace utilisĆ© pour atteindre votre + fichier (relatif Ć  l'application ou au plugin dans lequel vous faites le + ``bake``). Dans le cadre de l'exemple ci-dessus, cela crĆ©erait le test avec le + namespace ``App\Test\TestCase\Foo``. + +.. meta:: + :title lang=fr: Etendre Bake + :keywords lang=fr: interface ligne de commande,development,bake view, bake template syntax,erb tags,asp tags,percent tags diff --git a/app/vendor/cakephp/bake/docs/fr/index.rst b/app/vendor/cakephp/bake/docs/fr/index.rst new file mode 100644 index 000000000..c086cac49 --- /dev/null +++ b/app/vendor/cakephp/bake/docs/fr/index.rst @@ -0,0 +1,26 @@ +Console Bake +############ + +La console Bake de CakePHP est un autre outil permettant de rĆ©aliser son +application rapidement. La console Bake peut crĆ©er chacun des ingrĆ©dients +basiques de CakePHP : models, behaviors, views, helpers, controllers, +components, cas de tests, fixtures et plugins. Et nous ne parlons pas +seulement des squelettes de classes : Bake peut crĆ©er une application +fonctionnelle complĆØte en seulement quelques minutes. En rĆ©alitĆ©, Bake est une +Ć©tape naturelle Ć  suivre une fois qu'une application a Ć©tĆ© prototypĆ©e. + +Installation +============ + +Avant d'essayer d'utiliser ou d'Ć©tendre bake, assurez-vous qu'il est installĆ© +dans votre application. Bake est disponible en tant que plugin que vous pouvez +installer avec Composer:: + + composer require --dev cakephp/bake:~1.0 + +Ceci va installer bake en tant que dĆ©pendance de dĆ©veloppement. Cela signifie +qu'il ne sera pas installĆ© lors d'un dĆ©ploiement en production. + +.. meta:: + :title lang=fr: Console Bake + :keywords lang=fr: interface ligne de commande,development,bake view, bake template syntaxe,erb tags,asp tags,percent tags diff --git a/app/vendor/cakephp/bake/docs/fr/usage.rst b/app/vendor/cakephp/bake/docs/fr/usage.rst new file mode 100644 index 000000000..56e891a19 --- /dev/null +++ b/app/vendor/cakephp/bake/docs/fr/usage.rst @@ -0,0 +1,108 @@ +GĆ©nĆ©ration de Code avec Bake +############################ + +Suivant la configuration de votre installation, vous devrez peut ĆŖtre donner +les droits d'exĆ©cution au script bash cake ou l'appeler avec la commande +``./bin/cake bake``. +La console cake est exĆ©cutĆ©e en utilisant le CLI PHP +(Interface de Ligne de Commande). Si vous avez des problĆØmes en exĆ©cutant ce +script, vĆ©rifiez que : + +#. le CLI PHP est installĆ© et qu'il a les bons modules activĆ©s (ex: MySQL, intl). +#. Certains utilisateurs peuvent aussi rencontrer des problĆØmes si la base de + donnĆ©es host est 'localhost' et devront essayer '127.0.0.1' Ć  la place. +#. Selon la configuration de votre ordinateur, vous devrez peut-ĆŖtre permettre + l'exĆ©cution du script bash pour permettre de lancer ``bin/cake bake``. + +Avant de lancer bake, vous devrez vous assurer qu'au moins une connection Ć  une +base de donnĆ©es est configurĆ©e. + +Si vous exĆ©cutez la commande sans argument, ``bin/cake bake`` affichera la liste +des tĆ¢ches disponibles. Vous devriez voir quelque chose comme ceci:: + + $ bin/cake bake + + Welcome to CakePHP v3.x.x Console + --------------------------------------------------------------- + App : src + Path: /var/www/cakephp.dev/src/ + --------------------------------------------------------------- + Les commandes suivantes avec lesquelles vous pouvez gĆ©nĆ©rer un squelette de + code pour votre application. + + Les commandes disponibles de bake: + + - all + - behavior + - cell + - component + - controller + - fixture + - form + - helper + - mailer + - migration + - migration_snapshot + - model + - plugin + - shell + - shell-helper + - template + - test + + En utilisant `cake bake [name]` vous pouvez faire appel Ć  une tĆ¢che + spĆ©cifique de bake. + +Vous pouvez obtenir plus d'informations sur ce que chaque tĆ¢che fait et les +options disponibles en utilisant l'option ``--help``:: + + $ bin/cake bake controller --help + + Welcome to CakePHP v3.x.x Console + --------------------------------------------------------------- + App : src + Path: /var/www/cakephp.dev/src/ + --------------------------------------------------------------- + Bake a controller skeleton. + + Usage: + cake bake controller [subcommand] [options] [] + + Subcommands: + + all Bake all controllers with CRUD methods. + + To see help on a subcommand use `cake bake controller [subcommand] --help` + + Options: + + --help, -h Display this help. + --verbose, -v Enable verbose output. + --quiet, -q Enable quiet output. + --plugin, -p Plugin to bake into. + --force, -f Force overwriting existing files without prompting. + --connection, -c The datasource connection to get data from. + (default: default) + --theme, -t The theme to use when baking code. + --components The comma separated list of components to use. + --helpers The comma separated list of helpers to use. + --prefix The namespace/routing prefix to use. + --no-test Do not generate a test skeleton. + --no-actions Do not generate basic CRUD action methods. + + Arguments: + + name Name of the controller to bake. Can use Plugin.name to bake + controllers into plugins. (optional) + +Themes de Bake +============== + +L'option theme est commune Ć  toutes les commandes de bake, et permet de changer +les fichiers de template utilisĆ©s lors de la crĆ©ation avec bake. Pour crĆ©er vos +propres templates, rĆ©fĆ©rez-vous :ref:`Ć  la documentation sur la crĆ©ation de +theme bake `. + +.. meta:: + :title lang=fr: GĆ©nĆ©ration de Code avec Bake + :keywords lang=fr: interface ligne de commande,application fonctionnelle,base de donnĆ©es,configuration base de donnĆ©es,bash script,ingredients basiques,project,model,path path,gĆ©nĆ©ration de code,scaffolding,windows users,configuration file,few minutes,config,iew,shell,models,running,mysql diff --git a/app/vendor/cakephp/bake/docs/ja/conf.py b/app/vendor/cakephp/bake/docs/ja/conf.py new file mode 100644 index 000000000..5871da648 --- /dev/null +++ b/app/vendor/cakephp/bake/docs/ja/conf.py @@ -0,0 +1,9 @@ +import sys, os + +# Append the top level directory of the docs, so we can import from the config dir. +sys.path.insert(0, os.path.abspath('..')) + +# Pull in all the configuration options defined in the global config file.. +from config.all import * + +language = 'ja' diff --git a/app/vendor/cakephp/bake/docs/ja/contents.rst b/app/vendor/cakephp/bake/docs/ja/contents.rst new file mode 100644 index 000000000..08c3e957c --- /dev/null +++ b/app/vendor/cakephp/bake/docs/ja/contents.rst @@ -0,0 +1,7 @@ +.. toctree:: + :maxdepth: 2 + :caption: CakePHP Bake + + /index + /usage + /development diff --git a/app/vendor/cakephp/bake/docs/ja/development.rst b/app/vendor/cakephp/bake/docs/ja/development.rst new file mode 100644 index 000000000..a7d733edc --- /dev/null +++ b/app/vendor/cakephp/bake/docs/ja/development.rst @@ -0,0 +1,301 @@ +Bake の拔張 +########### + +Bake ćÆć€ć‚¢ćƒ—ćƒŖć‚±ćƒ¼ć‚·ćƒ§ćƒ³ć‚„ćƒ—ćƒ©ć‚°ć‚¤ćƒ³ćŒåŸŗęœ¬ę©Ÿčƒ½ć«åÆ¾ć—ć¦å¤‰ę›“ć¾ćŸćÆčæ½åŠ ć‚’åÆčƒ½ć«ć™ć‚‹ +ę‹”å¼µåÆčƒ½ćŖć‚¢ćƒ¼ć‚­ćƒ†ć‚Æćƒćƒ£ćƒ¼ć‚’å‚™ćˆć¦ć„ć¾ć™ć€‚Bake は、 `Twig `_ +ćƒ†ćƒ³ćƒ—ćƒ¬ćƒ¼ćƒˆć‚Øćƒ³ć‚øćƒ³ć‚’ä½æē”Øć—ćŸćƒ“ćƒ„ćƒ¼ć‚Æćƒ©ć‚¹ć‚’åˆ©ē”Øć—ć¾ć™ć€‚ + +Bake ć‚¤ćƒ™ćƒ³ćƒˆ +============= + +``BakeView`` ćÆć€ćƒ“ćƒ„ćƒ¼ć‚Æćƒ©ć‚¹ćØć—ć¦ć€ä»–ć®ćƒ“ćƒ„ćƒ¼ć‚Æćƒ©ć‚¹ćØåŒę§˜ć®ć‚¤ćƒ™ćƒ³ćƒˆć«åŠ ćˆć€ +1ć¤ć®ē‰¹åˆ„ćŖåˆęœŸåŒ– (initialize) ć‚¤ćƒ™ćƒ³ćƒˆć‚’ē™ŗć—ć¾ć™ć€‚ć—ć‹ć—ć€äø€ę–¹ć§ęØ™ęŗ–ćƒ“ćƒ„ćƒ¼ć‚Æćƒ©ć‚¹ćÆć€ +ć‚¤ćƒ™ćƒ³ćƒˆć®ćƒ—ćƒ¬ćƒ•ć‚£ćƒƒć‚Æć‚¹ "View." ć‚’ä½æē”Øć—ć¾ć™ćŒć€ ``BakeView`` は、 +ć‚¤ćƒ™ćƒ³ćƒˆć®ćƒ—ćƒ¬ćƒ•ć‚£ćƒƒć‚Æć‚¹ "Bake." を使用しています。 + +åˆęœŸåŒ–ć‚¤ćƒ™ćƒ³ćƒˆćÆć€ć™ć¹ć¦ć® bake ć®å‡ŗåŠ›ć«åÆ¾ć—ć¦å¤‰ę›“ć‚’åŠ ćˆć‚‹ćŸć‚ć«ä½æē”Øć§ćć¾ć™ć€‚ +ä¾‹ćˆć°ć€bake ćƒ“ćƒ„ćƒ¼ć‚Æćƒ©ć‚¹ć«ä»–ć®ćƒ˜ćƒ«ćƒ‘ćƒ¼ć‚’čæ½åŠ ć™ć‚‹ćŸć‚ć«ć“ć®ć‚¤ćƒ™ćƒ³ćƒˆćÆä½æē”Øć•ć‚Œć¾ć™ć€‚ :: + + on('Bake.initialize', function (Event $event) { + $view = $event->getSubject(); + + // bake ćƒ†ćƒ³ćƒ—ćƒ¬ćƒ¼ćƒˆć®äø­ć§ MySpecial ćƒ˜ćƒ«ćƒ‘ćƒ¼ć®ä½æē”Øć‚’åÆčƒ½ć«ć—ć¾ć™ + $view->loadHelper('MySpecial', ['some' => 'config']); + + // ćć—ć¦ć€$author å¤‰ę•°ć‚’åˆ©ē”ØåÆčƒ½ć«ć™ć‚‹ćŸć‚ć«čæ½åŠ  + $view->set('author', 'Andy'); + + }); + +åˆ„ć®ćƒ—ćƒ©ć‚°ć‚¤ćƒ³ć®äø­ć‹ć‚‰ bake ć‚’å¤‰ę›“ć—ćŸć„å “åˆćÆć€ćƒ—ćƒ©ć‚°ć‚¤ćƒ³ć® ``config/bootstrap.php`` +ćƒ•ć‚”ć‚¤ćƒ«ć§ćƒ—ćƒ©ć‚°ć‚¤ćƒ³ć® Bake ć‚¤ćƒ™ćƒ³ćƒˆć‚’ē½®ćć“ćØćÆč‰Æć„ć‚¢ć‚¤ćƒ‡ć‚¢ć§ć™ć€‚ + +Bake ć‚¤ćƒ™ćƒ³ćƒˆćÆć€ę—¢å­˜ć®ćƒ†ćƒ³ćƒ—ćƒ¬ćƒ¼ćƒˆć«å°ć•ćŖå¤‰ę›“ć‚’č”Œć†ćŸć‚ć®ä¾æåˆ©ćŖć“ćØćŒć§ćć¾ć™ć€‚ +ä¾‹ćˆć°ć€ć‚³ćƒ³ćƒˆćƒ­ćƒ¼ćƒ©ćƒ¼ć‚„ćƒ†ćƒ³ćƒ—ćƒ¬ćƒ¼ćƒˆćƒ•ć‚”ć‚¤ćƒ«ć‚’ bake ć™ć‚‹éš›ć«ä½æē”Øć•ć‚Œć‚‹å¤‰ę•°åć‚’ +å¤‰ę›“ć™ć‚‹ćŸć‚ć«ć€bake ćƒ†ćƒ³ćƒ—ćƒ¬ćƒ¼ćƒˆć§ä½æē”Øć•ć‚Œć‚‹å¤‰ę•°ć‚’å¤‰ę›“ć™ć‚‹ćŸć‚ć« +``Bake.beforeRender`` ć§å‘¼ć³å‡ŗć•ć‚Œć‚‹é–¢ę•°ć‚’ä½æē”Øć™ć‚‹ć“ćØćŒć§ćć¾ć™ć€‚ :: + + on('Bake.beforeRender', function (Event $event) { + $view = $event->getSubject(); + + // indexes ć®äø­ć®ćƒ”ć‚¤ćƒ³ćƒ‡ćƒ¼ć‚æå¤‰ę•°ć« $rows を使用 + if ($view->get('pluralName')) { + $view->set('pluralName', 'rows'); + } + if ($view->get('pluralVar')) { + $view->set('pluralVar', 'rows'); + } + + // view と edit ć®äø­ć®ćƒ”ć‚¤ćƒ³ćƒ‡ćƒ¼ć‚æå¤‰ę•°ć« $theOne を使用 + if ($view->get('singularName')) { + $view->set('singularName', 'theOne'); + } + if ($view->get('singularVar')) { + $view->set('singularVar', 'theOne'); + } + + }); + +ē‰¹å®šć®ē”Ÿęˆć•ć‚ŒćŸćƒ•ć‚”ć‚¤ćƒ«ćøć® ``Bake.beforeRender`` と ``Bake.afterRender`` +ć‚¤ćƒ™ćƒ³ćƒˆć‚’ęŒ‡å®šć™ć‚‹ć“ćØć‚‚ć‚ć‚‹ć§ć—ć‚‡ć†ć€‚ä¾‹ćˆć°ć€ +**Controller/controller.twig** ćƒ•ć‚”ć‚¤ćƒ«ć‹ć‚‰ē”Ÿęˆć™ć‚‹éš›ć€ UsersController +ć«ē‰¹å®šć®ć‚¢ć‚Æć‚·ćƒ§ćƒ³ć‚’čæ½åŠ ć—ćŸć„å “åˆć€ä»„äø‹ć®ć‚¤ćƒ™ćƒ³ćƒˆć‚’ä½æē”Øć™ć‚‹ć“ćØćŒć§ćć¾ć™ć€‚ :: + + on( + 'Bake.beforeRender.Controller.controller', + function (Event $event) { + $view = $event->getSubject(); + if ($view->viewVars['name'] == 'Users') { + // Users ć‚³ćƒ³ćƒˆćƒ­ćƒ¼ćƒ©ćƒ¼ć« login と logout ć‚’čæ½åŠ  + $view->viewVars['actions'] = [ + 'login', + 'logout', + 'index', + 'view', + 'add', + 'edit', + 'delete' + ]; + } + } + ); + +ē‰¹å®šć® bake ćƒ†ćƒ³ćƒ—ćƒ¬ćƒ¼ćƒˆć®ćŸć‚ć®ć‚¤ćƒ™ćƒ³ćƒˆćƒŖć‚¹ćƒŠćƒ¼ć‚’ęŒ‡å®šć™ć‚‹ć“ćØć«ć‚ˆć£ć¦ć€ +bake é–¢é€£ć®ć‚¤ćƒ™ćƒ³ćƒˆćƒ»ćƒ­ć‚øćƒƒć‚Æć‚’ē°”ē“ åŒ–ć—ć€ćƒ†ć‚¹ćƒˆć™ć‚‹ć®ćŒå®¹ę˜“ć§ć‚ć‚‹ć‚³ćƒ¼ćƒ«ćƒćƒƒć‚Æć‚’ +ęä¾›ć™ć‚‹ć“ćØćŒć§ćć¾ć™ć€‚ + +Bake ćƒ†ćƒ³ćƒ—ćƒ¬ćƒ¼ćƒˆę§‹ę–‡ +===================== + +Bake ćƒ†ćƒ³ćƒ—ćƒ¬ćƒ¼ćƒˆćƒ•ć‚”ć‚¤ćƒ«ćÆć€ `Twig `__ +ćƒ†ćƒ³ćƒ—ćƒ¬ćƒ¼ćƒˆę§‹ę–‡ć‚’ä½æē”Øć—ć¾ć™ć€‚ + +bake ćƒ†ćƒ³ćƒ—ćƒ¬ćƒ¼ćƒˆćŒć©ć®ć‚ˆć†ć«å‹•ä½œć™ć‚‹ć‹ć‚’ē¢ŗčŖ/理解する一つの方法は、 +bake ćƒ†ćƒ³ćƒ—ćƒ¬ćƒ¼ćƒˆćƒ•ć‚”ć‚¤ćƒ«ć‚’å¤‰ę›“ć—ć‚ˆć†ćØć™ć‚‹å “åˆćÆē‰¹ć«ć€ć‚Æćƒ©ć‚¹ć‚’ bake 恗恦态 +ć‚¢ćƒ—ćƒŖć‚±ćƒ¼ć‚·ćƒ§ćƒ³ć® **tmp/bake** ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼å†…ć«ę®‹ć£ć¦ć„ć‚‹å‰å‡¦ē†ć•ć‚ŒćŸćƒ†ćƒ³ćƒ—ćƒ¬ćƒ¼ćƒˆćƒ•ć‚”ć‚¤ćƒ«ć‚’ +ä½æć£ćŸćƒ†ćƒ³ćƒ—ćƒ¬ćƒ¼ćƒˆćØęÆ”č¼ƒć™ć‚‹ć“ćØć§ć™ć€‚ + +ć ć‹ć‚‰ć€ä¾‹ćˆć°ć€ä»„äø‹ć®ć‚ˆć†ć«ć‚·ć‚§ćƒ«ć‚’ bake ć—ćŸå “åˆ: + +.. code-block:: bash + + bin/cake bake shell Foo + +(**vendor/cakephp/bake/src/Template/Bake/Shell/shell.twig**) ć‚’ä½æē”Øć—ćŸ +ćƒ†ćƒ³ćƒ—ćƒ¬ćƒ¼ćƒˆćÆć€ä»„äø‹ć®ć‚ˆć†ć«ćŖć‚Šć¾ć™ć€‚ :: + + `` Bake ćƒ†ćƒ³ćƒ—ćƒ¬ćƒ¼ćƒˆć® PHP 終了タグ + * ``<%=`` Bake ćƒ†ćƒ³ćƒ—ćƒ¬ćƒ¼ćƒˆć® PHP ć‚·ćƒ§ćƒ¼ćƒˆć‚Øć‚³ćƒ¼ć‚æć‚° + * ``<%-`` Bake ćƒ†ćƒ³ćƒ—ćƒ¬ćƒ¼ćƒˆć® PHP é–‹å§‹ć‚æć‚°ć€ć‚æć‚°ć®å‰ć«ć€å…ˆé ­ć®ē©ŗē™½ć‚’é™¤åŽ» + * ``-%>`` Bake ćƒ†ćƒ³ćƒ—ćƒ¬ćƒ¼ćƒˆć® PHP ēµ‚äŗ†ć‚æć‚°ć€ć‚æć‚°ć®å¾Œć«ęœ«å°¾ć®ē©ŗē™½ć‚’é™¤åŽ» + +.. _creating-a-bake-theme: + +Bake ćƒ†ćƒ¼ćƒžć®ä½œęˆ +================= + +"bake" ć‚³ćƒžćƒ³ćƒ‰ć«ć‚ˆć£ć¦ē”Ÿęˆć•ć‚ŒćŸå‡ŗåŠ›ć‚’å¤‰ę›“ć—ćŸć„å “åˆć€bake ćŒä½æē”Øć™ć‚‹ćƒ†ćƒ³ćƒ—ćƒ¬ćƒ¼ćƒˆć® +äø€éƒØć¾ćŸćÆå…ØéƒØć‚’ē½®ćę›ćˆć‚‹ć“ćØćŒć§ćć‚‹ć€ē‹¬č‡Ŗć® bake ć®ć€Œćƒ†ćƒ¼ćƒžć€ć‚’ä½œęˆć™ć‚‹ć“ćØćŒć§ćć¾ć™ć€‚ +ć“ć‚Œć‚’č”Œć†ćŸć‚ć®ęœ€å–„ć®ę–¹ę³•ćÆć€ę¬”ć®ćØćŠć‚Šć§ć™ć€‚ + +#. ę–°ć—ć„ćƒ—ćƒ©ć‚°ć‚¤ćƒ³ć‚’ bake ć—ć¾ć™ć€‚ćƒ—ćƒ©ć‚°ć‚¤ćƒ³ć®åå‰ćÆ bake ć®ć€Œćƒ†ćƒ¼ćƒžć€åć«ćŖć‚Šć¾ć™ć€‚ +#. ę–°ć—ć„ćƒ‡ć‚£ćƒ¬ć‚ÆćƒˆćƒŖćƒ¼ **plugins/[name]/src/Template/Bake/Template/** ć‚’ä½œęˆć—ć¾ć™ć€‚ +#. **vendor/cakephp/bake/src/Template/Bake/Template** ć‹ć‚‰äøŠę›øćć—ćŸć„ + ćƒ†ćƒ³ćƒ—ćƒ¬ćƒ¼ćƒˆć‚’ć‚ćŖćŸć®ćƒ—ćƒ©ć‚°ć‚¤ćƒ³ć®äø­ć®é©åˆ‡ćŖćƒ•ć‚”ć‚¤ćƒ«ć«ć‚³ćƒ”ćƒ¼ć—ć¦ćć ć•ć„ć€‚ +#. bake ć‚’å®Ÿč”Œć™ć‚‹ćØćć«ć€åæ…č¦ć§ć‚ć‚Œć°ć€ bake ć®ćƒ†ćƒ¼ćƒžć‚’ęŒ‡å®šć™ć‚‹ćŸć‚ć® ``--theme`` + ć‚Ŗćƒ—ć‚·ćƒ§ćƒ³ć‚’ä½æē”Øć—ć¦ćć ć•ć„ć€‚å„å‘¼ć³å‡ŗć—ć§ć“ć®ć‚Ŗćƒ—ć‚·ćƒ§ćƒ³ć‚’ęŒ‡å®šć—ćŖćć¦ć‚‚ęøˆć‚€ć‚ˆć†ć«ć€ + ć‚«ć‚¹ć‚æćƒ ćƒ†ćƒ¼ćƒžć‚’ćƒ‡ćƒ•ć‚©ćƒ«ćƒˆćƒ†ćƒ¼ćƒžćØć—ć¦ä½æē”Øć™ć‚‹ć‚ˆć†ć«čØ­å®šć™ć‚‹ć“ćØć‚‚ć§ćć¾ć™ć€‚ :: + + Test->classSuffixes[$this->name()])) { + $this->Test->classSuffixes[$this->name()] = 'Foo'; + } + + $name = ucfirst($this->name()); + if (!isset($this->Test->classTypes[$name])) { + $this->Test->classTypes[$name] = 'Foo'; + } + + return parent::bakeTest($className); + } + +* **class suffix** は ``bake`` å‘¼ć³å‡ŗć—ć§äøŽćˆć‚‰ć‚ŒćŸåå‰ć«čæ½åŠ ć—ć¾ć™ć€‚å‰ć®ä¾‹ć§ćÆć€ + ``ExampleFooTest.php`` ćƒ•ć‚”ć‚¤ćƒ«ć‚’ä½œęˆć—ć¾ć™ć€‚ +* **class type** ćÆć€ļ¼ˆć‚ćŖćŸćŒ bake ć™ć‚‹ć‚¢ćƒ—ćƒŖć‚„ćƒ—ćƒ©ć‚°ć‚¤ćƒ³ć«é–¢é€£ć™ć‚‹ļ¼‰ + ć‚ćŖćŸć®ćƒ•ć‚”ć‚¤ćƒ«ć‚’å°ŽććŸć‚ć«ä½æē”Øć•ć‚Œć‚‹ć‚µćƒ–åå‰ē©ŗé–“ć§ć™ć€‚ + å‰ć®ä¾‹ć§ćÆć€åå‰ē©ŗé–“ ``App\Test\TestCase\Foo`` ć§ćƒ†ć‚¹ćƒˆć‚’ä½œęˆć—ć¾ć™ć€‚ + +.. meta:: + :title lang=ja: Bake の拔張 + :keywords lang=ja: command line interface,development,bake view, bake template syntax,twig,erb tags,percent tags diff --git a/app/vendor/cakephp/bake/docs/ja/index.rst b/app/vendor/cakephp/bake/docs/ja/index.rst new file mode 100644 index 000000000..a4e503963 --- /dev/null +++ b/app/vendor/cakephp/bake/docs/ja/index.rst @@ -0,0 +1,28 @@ +Bake ć‚³ćƒ³ć‚½ćƒ¼ćƒ« +################ + +CakePHP 恮 bake ć‚³ćƒ³ć‚½ćƒ¼ćƒ«ćÆć€čæ…é€Ÿć« CakePHP ć‚’å‹•ä½œć•ć›ć‚‹ć¾ć§ć‚’ę”Æę“ć—ć¾ć™ć€‚ +bake ć‚³ćƒ³ć‚½ćƒ¼ćƒ«ćÆć€CakePHP ć®åŸŗęœ¬ēš„ćŖē“ ę(ćƒ¢ćƒ‡ćƒ«ć€ćƒ“ćƒ˜ć‚¤ćƒ“ć‚¢ćƒ¼ć€ćƒ“ćƒ„ćƒ¼ć€ćƒ˜ćƒ«ćƒ‘ćƒ¼ć€ +ć‚³ćƒ³ćƒˆćƒ­ćƒ¼ćƒ©ćƒ¼ć€ć‚³ćƒ³ćƒćƒ¼ćƒćƒ³ćƒˆć€ćƒ†ć‚¹ćƒˆć‚±ćƒ¼ć‚¹ć€ćƒ•ć‚£ć‚Æć‚¹ćƒćƒ£ćƒ¼ć€ćƒ—ćƒ©ć‚°ć‚¤ćƒ³)ć‚’ä½œęˆć§ćć¾ć™ć€‚ +ćć®ē‚ŗć®ć‚¹ć‚±ćƒ«ćƒˆćƒ³ć‚Æćƒ©ć‚¹ć«ć¤ć„ć¦ćÆć€ć“ć“ć§ćÆēœē•„ć—ć¾ć™ćŒć€ +bake ćÆę•°åˆ†ć§å®Œå…Øć«ę©Ÿčƒ½ć™ć‚‹ć‚¢ćƒ—ćƒŖć‚±ćƒ¼ć‚·ćƒ§ćƒ³ć‚’ä½œęˆć§ćć¾ć™ć€‚ +要恙悋恫态bake ćÆč¶³å “ć®ēµ„ć¾ć‚ŒćŸć‚¢ćƒ—ćƒŖć‚±ćƒ¼ć‚·ćƒ§ćƒ³ć‚’ć„ć£ćŗć‚“ć«ę‰‹ć«å…„ć‚Œć‚‹ćŸć‚ć«ć†ć£ć¦ć¤ć‘ć®ę–¹ę³•ć§ć™ć€‚ + +ć‚¤ćƒ³ć‚¹ćƒˆćƒ¼ćƒ«ę‰‹é † +================= + +bake ć‚’ä½æē”Øć—ćŸć‚Šę‹”å¼µć™ć‚‹å‰ć«ć€ć‚¢ćƒ—ćƒŖć‚±ćƒ¼ć‚·ćƒ§ćƒ³ć« bake ć‚’ć‚¤ćƒ³ć‚¹ćƒˆćƒ¼ćƒ«ć—ć¦ćŠć„ć¦ćć ć•ć„ć€‚ +bake は Composer ć‚’ä½æć£ć¦ć‚¤ćƒ³ć‚¹ćƒˆćƒ¼ćƒ«ć™ć‚‹ćƒ—ćƒ©ć‚°ć‚¤ćƒ³ćØć—ć¦ęä¾›ć•ć‚Œć¦ć„ć¾ć™ć€‚ :: + + composer require --dev cakephp/bake:"^2.0" + +äøŠčØ˜ć®ć‚³ćƒžćƒ³ćƒ‰ćÆć€bake ć‚’é–‹ē™ŗē’°å¢ƒć§ä½æē”Øć™ć‚‹ćƒ‘ćƒƒć‚±ćƒ¼ć‚øćØć—ć¦ć‚¤ćƒ³ć‚¹ćƒˆćƒ¼ćƒ«ć—ć¾ć™ć€‚ +ć“ć®å…„ć‚Œę–¹ć®å “åˆć€ęœ¬ē•Ŗē’°å¢ƒćØć—ć¦ćƒ‡ćƒ—ćƒ­ć‚¤ć™ć‚‹éš›ć«ćÆć€ bake ćÆć‚¤ćƒ³ć‚¹ćƒˆćƒ¼ćƒ«ć•ć‚Œć¾ć›ć‚“ć€‚ + +Twig ćƒ†ćƒ³ćƒ—ćƒ¬ćƒ¼ćƒˆć‚’ä½æē”Øć™ć‚‹å “åˆć€ ``Cake/TwigView`` ćƒ—ćƒ©ć‚°ć‚¤ćƒ³ć‚’ćƒ–ćƒ¼ćƒˆć‚¹ćƒˆćƒ©ćƒƒćƒ—ćØćØć‚‚ć« +čŖ­ćæč¾¼ć‚“ć§ć„ć‚‹ć“ćØć‚’ē¢ŗčŖć—ć¦ćć ć•ć„ć€‚ćć‚Œć‚’å®Œå…Øć«ēœē•„ć—ć¦ć€ +Bake ćƒ—ćƒ©ć‚°ć‚¤ćƒ³ć«ć“ć®ćƒ—ćƒ©ć‚°ć‚¤ćƒ³ć‚’čŖ­ćæč¾¼ć¾ć›ć‚‹ć“ćØć‚‚ć§ćć¾ć™ć€‚ + +.. meta:: + :title lang=ja: Bakeć‚³ćƒ³ć‚½ćƒ¼ćƒ« + :keywords lang=ja: ć‚³ćƒžćƒ³ćƒ‰ćƒ©ć‚¤ćƒ³,CLI,development,bake view, bake template syntax,erb tags,asp tags,percent tags diff --git a/app/vendor/cakephp/bake/docs/ja/usage.rst b/app/vendor/cakephp/bake/docs/ja/usage.rst new file mode 100644 index 000000000..d9470e6c3 --- /dev/null +++ b/app/vendor/cakephp/bake/docs/ja/usage.rst @@ -0,0 +1,102 @@ +Bake ć§ć‚³ćƒ¼ćƒ‰ē”Ÿęˆ +################## + +cake ć‚³ćƒ³ć‚½ćƒ¼ćƒ«ćÆć€ PHP CLI (command line interface) ć§å®Ÿč”Œć—ć¾ć™ć€‚ +ć‚‚ć—ć‚¹ć‚ÆćƒŖćƒ—ćƒˆć®å®Ÿč”Œć«å•é”ŒćŒć‚ć‚‹ćŖć‚‰ć€ä»„äø‹ć‚’ęŗ€ćŸć—ć¦ćć ć•ć„ć€‚ + +#. PHP CLI ćŒć‚¤ćƒ³ć‚¹ćƒˆćƒ¼ćƒ«ć•ć‚Œć¦ć„ć‚‹ć‹é©åˆ‡ćŖćƒ¢ć‚øćƒ„ćƒ¼ćƒ«ćŒęœ‰åŠ¹ć‹ē¢ŗčŖć—ć¦ćć ć•ć„ (ä¾‹ļ¼šMySQL, intl)怂 +#. ćƒ‡ćƒ¼ć‚æćƒ™ćƒ¼ć‚¹ć®ćƒ›ć‚¹ćƒˆćŒ 'localhost' ć§å•é”ŒćŒć‚ć‚‹ćŖć‚‰ć€ä»£ć‚ć‚Šć« '127.0.0.1' を使って下さい。 + PHP CLI ć§ć“ć®å•é”ŒćŒćŠć“ć‚‹åÆčƒ½ę€§ćŒć‚ć‚Šć¾ć™ć€‚ +#. ä½æć£ć¦ć„ć‚‹ć‚³ćƒ³ćƒ”ćƒ„ćƒ¼ć‚æćƒ¼ć®čØ­å®šć«åæœć˜ć¦ć€ ``bin/cake bake`` で使用する cake bash ć‚¹ć‚ÆćƒŖćƒ—ćƒˆć® + å®Ÿč”ŒęØ©é™ć‚’čØ­å®šć™ć‚‹åæ…č¦ćŒć‚ć‚Šć¾ć™ć€‚ + +bake ć‚’å®Ÿč”Œć™ć‚‹å‰ć«ćƒ‡ćƒ¼ć‚æćƒ™ćƒ¼ć‚¹ćØć®ęŽ„ē¶šć‚’ē¢ŗčŖć—ć¾ć—ć‚‡ć†ć€‚ + +``bin/cake bake`` ć‚’å¼•ę•°ē„”ć—ć§å®Ÿč”Œć™ć‚‹ćØåÆčƒ½ćŖć‚æć‚¹ć‚Æć‚’č”Øē¤ŗć§ćć¾ć™ć€‚ + +Windows ć‚·ć‚¹ćƒ†ćƒ ć®å “åˆć€ ``bin\cake bake`` ć‚’č©¦ć—ć¦ćæć¦ćć ć•ć„ć€‚ + +ćć‚ŒćÆä»„äø‹ć®ć‚ˆć†ć«č”Øē¤ŗć•ć‚Œć¾ć™ć€‚ :: + + $ bin/cake bake + + Welcome to CakePHP v3.1.6 Console + --------------------------------------------------------------- + App : src + Path: /var/www/cakephp.dev/src/ + PHP: 5.5.8 + --------------------------------------------------------------- + The following commands can be used to generate skeleton code for your application. + + Available bake commands: + + - all + - behavior + - cell + - component + - controller + - fixture + - form + - helper + - mailer + - migration + - migration_snapshot + - model + - plugin + - shell + - shell-helper + - template + - test + + By using `cake bake [name]` you can invoke a specific bake task. + +ć‚ˆć‚Šč©³ć—ć„å„ć‚³ćƒžćƒ³ćƒ‰ć®ęƒ…å ±ć‚’å¾—ć‚‹ć«ćÆć€ ``--help`` ć‚Ŗćƒ—ć‚·ćƒ§ćƒ³ć‚’ć¤ć‘å®Ÿč”Œć—ć¦ćć ć•ć„ć€‚ :: + + $ bin/cake bake controller --help + + Welcome to CakePHP v3.1.6 Console + --------------------------------------------------------------- + App : src + Path: /var/www/cakephp.dev/src/ + --------------------------------------------------------------- + Bake a controller skeleton. + + Usage: + cake bake controller [subcommand] [options] [] + + Subcommands: + + all Bake all controllers with CRUD methods. + + To see help on a subcommand use `cake bake controller [subcommand] --help` + + Options: + + --help, -h Display this help. + --verbose, -v Enable verbose output. + --quiet, -q Enable quiet output. + --plugin, -p Plugin to bake into. + --force, -f Force overwriting existing files without prompting. + --connection, -c The datasource connection to get data from. + (default: default) + --theme, -t The theme to use when baking code. + --components The comma separated list of components to use. + --helpers The comma separated list of helpers to use. + --prefix The namespace/routing prefix to use. + --no-test Do not generate a test skeleton. + --no-actions Do not generate basic CRUD action methods. + + Arguments: + + name Name of the controller to bake. Can use Plugin.name to bake + controllers into plugins. (optional) + +Bake ćƒ†ćƒ¼ćƒžć‚Ŗćƒ—ć‚·ćƒ§ćƒ³ +===================== + +ćƒ†ćƒ¼ćƒžć‚Ŗćƒ—ć‚·ćƒ§ćƒ³ćÆå…Ø bake ć‚³ćƒžćƒ³ćƒ‰ć§äø€čˆ¬ēš„ć§ć™ć€‚ć¾ćŸć€bake ćƒ†ćƒ³ćƒ—ćƒ¬ćƒ¼ćƒˆćƒ•ć‚”ć‚¤ćƒ«ć‚’å¤‰ę›“ć™ć‚‹ć“ćØćŒć§ćć¾ć™ć€‚ +ćƒ†ćƒ¼ćƒžć‚’ä½œć‚‹ć«ćÆć€ :ref:`Bake ćƒ†ćƒ¼ćƒžä½œęˆćƒ‰ć‚­ćƒ„ćƒ”ćƒ³ćƒˆ ` ć‚’ć”č¦§ćć ć•ć„ć€‚ + +.. meta:: + :title lang=ja: Code Generation with Bake + :keywords lang=ja: command line interface,functional application,database,database configuration,bash script,basic ingredients,project,model,path path,code generation,scaffolding,windows users,configuration file,few minutes,config,iew,shell,models,running,mysql diff --git a/app/vendor/cakephp/bake/docs/pt/conf.py b/app/vendor/cakephp/bake/docs/pt/conf.py new file mode 100644 index 000000000..9e22cb017 --- /dev/null +++ b/app/vendor/cakephp/bake/docs/pt/conf.py @@ -0,0 +1,9 @@ +import sys, os + +# Append the top level directory of the docs, so we can import from the config dir. +sys.path.insert(0, os.path.abspath('..')) + +# Pull in all the configuration options defined in the global config file.. +from config.all import * + +language = 'pt' diff --git a/app/vendor/cakephp/bake/docs/pt/contents.rst b/app/vendor/cakephp/bake/docs/pt/contents.rst new file mode 100644 index 000000000..08c3e957c --- /dev/null +++ b/app/vendor/cakephp/bake/docs/pt/contents.rst @@ -0,0 +1,7 @@ +.. toctree:: + :maxdepth: 2 + :caption: CakePHP Bake + + /index + /usage + /development diff --git a/app/vendor/cakephp/bake/docs/pt/development.rst b/app/vendor/cakephp/bake/docs/pt/development.rst new file mode 100644 index 000000000..5e4fb05f8 --- /dev/null +++ b/app/vendor/cakephp/bake/docs/pt/development.rst @@ -0,0 +1,303 @@ +Estendendo o Bake +################# + +O Bake fornece uma arquitetura expansĆ­vel que permite a sua aplicação ou plugin +modificar ou adicionar funcionalidades Ć s suas funƧƵes bĆ”sicas. Bake faz uso de +uma classe view dedicada que usa a ferramenta de templates `Twig +`_. + +Eventos do Bake +=============== + +Como uma class view , ``BakeView`` emite o mesmo evento como qualquer outra +classe view, mais uma extra que inicializa eventos. No entanto, onde as classes +view padrĆ£o usam o prefixo "View.", ``BakeView`` usa o prefixo "Bake.". + +O inicializador de eventos pode ser usado para fazer mudanƧas quando aplicado +a todas as saĆ­das do Bake, por exemplo, ao adicionar outro helper Ć  classe bake +view este evento pode ser usado:: + + on('Bake.initialize', function (Event $event) { + $view = $event->getSubject(); + + // In my bake templates, allow the use of the MySpecial helper + $view->loadHelper('MySpecial', ['some' => 'config']); + + // And add an $author variable so it's always available + $view->set('author', 'Andy'); + + }); + +Se vocĆŖ deseja modificar o bake de outro plugin, Ć© recomendĆ”vel colocar os +eventos do bake do seu plugin no arquivo **config/bootstrap.php**. + +Os eventos do Bake podem ser Ćŗteis para fazer pequenas alteraƧƵes nos modelos +existentes. Por exemplo, para alterar os nomes das variĆ”veis usados no +controller/template quando executar o bake, pode-se usar uma função esperando +o ``Bake.beforeRender`` para modificar as variĆ”veis usadas no bake templates:: + + on('Bake.beforeRender', function (Event $event) { + $view = $event->getSubject(); + + // Use $rows for the main data variable in indexes + if ($view->get('pluralName')) { + $view->set('pluralName', 'rows'); + } + if ($view->get('pluralVar')) { + $view->set('pluralVar', 'rows'); + } + + // Use $theOne for the main data variable in view/edit + if ($view->get('singularName')) { + $view->set('singularName', 'theOne'); + } + if ($view->get('singularVar')) { + $view->set('singularVar', 'theOne'); + } + + }); + +VocĆŖ tambĆ©m pode abranger os eventos ``Bake.beforeRender`` +e ``Bake.afterRender`` para um arquivo especĆ­fico. Por exemplo, se vocĆŖ quiser +adicionar aƧƵes especĆ­ficas para seu UsersController ao gerar a partir de um +arquivo **Controller/controller.twig**, vocĆŖ pode usar o seguinte evento:: + + on( + 'Bake.beforeRender.Controller.controller', + function (Event $event) { + $view = $event->getSubject(); + if ($view->viewVars['name'] == 'Users') { + // add the login and logout actions to the Users controller + $view->set('actions', [ + 'login', + 'logout', + 'index', + 'view', + 'add', + 'edit', + 'delete' + ]); + } + } + ); + +Ao adicionar eventos que escutam um bake templates especĆ­fico, vocĆŖ pode +simplesmente relacionar a sua lógica de eventos com o bake e fornecer callbacks +que sĆ£o facilmente testĆ”veis. + +Sintaxe de Templates do Bake +============================ + +Os arquivos de templates do Bake usam a sintaxe `Twig `__. + +Uma forma de ver e entender como o bake funciona, especialmente quando tentamos +modificar os arquivos de templates, Ć© executar o bake de uma classe que compara +o template usado com o template prĆ©-processado deixado anteriormente pela +aplicação na pasta **tmp/bake**. + +EntĆ£o, por exemplo, quando vocĆŖ executar algo como:: + +.. code-block:: bash + + $ bin/cake bake shell Foo + +O template usado (**vendor/cakephp/bake/src/Template/Bake/Shell/shell.twig**) +parece com algo assim:: + + `` Um template bake php fecha a tag + * ``<%=`` Um template bake php short-echo tag + * ``<%-`` Um template bake php abre a tag, retirando qualquer espaƧo em branco antes da tag + * ``-%>`` Um template bake php fecha a tag, retirando qualqualquer espaƧo em branco após a tag + +.. _creating-a-bake-theme: + +Criando um Tema Bake +===================== + +Se vocĆŖ deseja modificar a saĆ­da produzida com o comando bake, vocĆŖ pode criar +o seu próprio tema para o bake que permitirĆ” vocĆŖ substituir algum ou todos os +tempaltes que o bake usa. O mmelhor jeito de fazer isto Ć©: + +#. Bake um novo plugin. O nome do plugin Ć© o 'nome do tema' +#. Crie uma nova pasta em **plugins/[name]/Template/Bake/Template/**. +#. Copie qualquer template que vocĆŖ queira modificar de + **vendor/cakephp/bake/src/Template/Bake/Template** para a pasta acima e modificĆ”-los conforme sua necessidade. +#. Quando executar o bake use a opção ``--theme`` para especificar qual o tema + que o bake deve usar. Para evitar problemas com esta opção, em cada chamada, + vocĆŖ tambĆ©m pode definir o seu template customizado para ser usado como + o template padrĆ£o:: + + Test->classSuffixes[$this->name()])) { + $this->Test->classSuffixes[$this->name()] = 'Foo'; + } + + $name = ucfirst($this->name()); + if (!isset($this->Test->classTypes[$name])) { + $this->Test->classTypes[$name] = 'Foo'; + } + + return parent::bakeTest($className); + } + +* O **sufixo da classe** serĆ” anexado ao nome fornecido em sua chamada bake. No + exemplo anterior, ele criaria um arquivo ExampleFooTest.php. +* O **tipo de classe** serĆ” o subdomĆ­nio usado que levarĆ” ao seu arquivo + (relativo ao aplicativo ou ao plugin em que vocĆŖ estĆ” inserindo). No exemplo + anterior, ele criaria seu teste com o namespace App\Test\TestCase\Foo. + + +.. meta:: + :title lang=en: Extending Bake + :keywords lang=en: command line interface,development,bake view, bake template syntax,twig,erb tags,percent tags + diff --git a/app/vendor/cakephp/bake/docs/pt/index.rst b/app/vendor/cakephp/bake/docs/pt/index.rst new file mode 100644 index 000000000..8d068757e --- /dev/null +++ b/app/vendor/cakephp/bake/docs/pt/index.rst @@ -0,0 +1,30 @@ +Console Bake +############ + +O console do **Bake** Ć© outra ferramenta disponĆ­vel para vocĆŖ sair trabalhando +- e rĆ”pido! O console Bake pode criar qualquer Ć­tem bĆ”sico do CakePHP: models, +behaviors, views, helpers, controllers, components, test cases, fixtures +e plugins. E nós nĆ£o estamos apenas falando do esqueleto da classes: O Bake +pode criar uma aplicação totalmente funcional em questĆ£o de minutos. De fato, +o Bake Ć© um passo natural a se dar uma vez que a aplicação tem sua base +construĆ­da. + +Instalação +========== + +Antes de tentar usar ou estender o Bake, tenha certeza de que ele estĆ” instalado em +sua aplicação. O Bake Ć© distribuĆ­do como um plugin que vocĆŖ pode instalar com o +Composer:: + + composer require --dev cakephp/bake:~2.0 + +Isto irĆ” instalar o Bake como uma dependĆŖncia de desenvolvimento, sendo assim, +nĆ£o serĆ” instalado no ambiente de produção. + +Ao usar os modelos Twig, verifique se vocĆŖ estĆ” carregando o plugin +Cake/TwigView com seu bootstrap. VocĆŖ tambĆ©m pode omiti-lo completamente, +o que faz com que o plugin Bake carregue esse plugin sob demanda. + +.. meta:: + :title lang=pt: Bake Console + :keywords lang=pt: cli,linha de comando,command line,dev,desenvolvimento,bake view, bake syntax,erb tags,asp tags,percent tags diff --git a/app/vendor/cakephp/bake/docs/pt/usage.rst b/app/vendor/cakephp/bake/docs/pt/usage.rst new file mode 100644 index 000000000..7d513a0f6 --- /dev/null +++ b/app/vendor/cakephp/bake/docs/pt/usage.rst @@ -0,0 +1,117 @@ +Geração de Código com Bake +########################## + +O console do **Bake** Ć© executado usando o PHP CLI (interface da linha de comando). +Se vocĆŖ tiver problemas para executar o script, assegure-se de que: + +#. VocĆŖ instalou o PHP CLI e possui os módulos apropriados habilitados (por + exemplo: MySQL, intl). +#. Os usuĆ”rios tambĆ©m podem ter problemas se o host do banco de dados for + 'localhost' e devem tentar '127.0.0.1', em vez disso, como localhost pode + causar problemas no PHP CLI. +#. Dependendo de como o seu computador estĆ” configurado, vocĆŖ pode ter que + definir direitos de execução no script cake bash para chamĆ”-lo usando + ``bin/cake bake``. + +Antes de executar o Bake vocĆŖ deve certificar-se de ter pelo menos um banco de dados com a conexĆ£o configurada. + +Para ver as opƧƵes disponĆ­veis no Bake digite:: + + $ bin/cake bake --help + + Current Paths: + + * app: src + * root: . + * core: .\vendor\cakephp\cakephp + + Available Commands: + + Bake: + - bake all + - bake behavior + - bake cell + - bake command + - bake component + - bake controller + - bake controller all + - bake fixture + - bake fixture all + - bake form + - bake helper + - bake mailer + - bake middleware + - bake model + - bake model all + - bake plugin + - bake shell + - bake shell_helper + - bake task + - bake template + - bake template all + - bake test + + To run a command, type `cake command_name [args|options]` + To get help on a specific command, type `cake command_name --help` + + +VocĆŖ pode obter mais informaƧƵes sobre o que cada tarefa faz e quais sĆ£o suas opƧƵes +disponĆ­veis usando a opção ``--help``:: + + $ bin/cake bake model --help + + Bake table and entity classes. + + Usage: + cake bake model [options] [] + + Options: + + --connection, -c The datasource connection to get data from. + (default: default) + --display-field The displayField if you would like to choose one. + --fields A comma separated list of fields to make + accessible. + --force, -f Force overwriting existing files without + prompting. + --help, -h Display this help. + --hidden A comma separated list of fields to hide. + --no-associations Disable generating associations. + --no-entity Disable generating an entity class. + --no-fields Disable generating accessible fields in the + entity. + --no-fixture Do not generate a test fixture skeleton. + --no-hidden Disable generating hidden fields in the entity. + --no-rules Disable generating a rules checker. + --no-table Disable generating a table class. + --no-test Do not generate a test case skeleton. + --no-validation Disable generating validation rules. + --plugin, -p Plugin to bake into. + --primary-key The primary key if you would like to manually set + one. Can be a comma separated list if you are + using a composite primary key. + --quiet, -q Enable quiet output. + --table The table name to use if you have + non-conventional table names. + --theme, -t The theme to use when baking code. + --verbose, -v Enable verbose output. + + Arguments: + + name Name of the model to bake (without the Table suffix). You can use + Plugin.name to bake plugin models. (optional) + + Omitting all arguments and options will list the table names you can + generate models for. + + + +Temas para o Bake +================= + +A opção de tema Ć© comum a todos os comandos do Bake e permite mudar os arquivos de modelo usados por ele. Para criar seus próprios modelos, veja a +:ref:`documentação de criação de temas para o Bake `. + +.. meta:: + :title lang=pt: Geração de código com bake + :keywords lang=pt: command line interface,functional application,database,database configuration,bash script,basic ingredients,project,model,path path,code generation,scaffolding,windows users,configuration file,few minutes,config,iew,shell,models,running,mysql diff --git a/app/vendor/cakephp/bake/docs/ru/conf.py b/app/vendor/cakephp/bake/docs/ru/conf.py new file mode 100644 index 000000000..f8a170ee5 --- /dev/null +++ b/app/vendor/cakephp/bake/docs/ru/conf.py @@ -0,0 +1,9 @@ +import sys, os + +# Append the top level directory of the docs, so we can import from the config dir. +sys.path.insert(0, os.path.abspath('..')) + +# Pull in all the configuration options defined in the global config file.. +from config.all import * + +language = 'ru' diff --git a/app/vendor/cakephp/bake/docs/ru/contents.rst b/app/vendor/cakephp/bake/docs/ru/contents.rst new file mode 100644 index 000000000..08c3e957c --- /dev/null +++ b/app/vendor/cakephp/bake/docs/ru/contents.rst @@ -0,0 +1,7 @@ +.. toctree:: + :maxdepth: 2 + :caption: CakePHP Bake + + /index + /usage + /development diff --git a/app/vendor/cakephp/bake/docs/ru/development.rst b/app/vendor/cakephp/bake/docs/ru/development.rst new file mode 100644 index 000000000..5b7de8ec8 --- /dev/null +++ b/app/vendor/cakephp/bake/docs/ru/development.rst @@ -0,0 +1,293 @@ +Š Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŠµ возможностей Bake +############################ + +Bake имеет Ń€Š°ŃŃˆŠøŃ€ŃŠµŠ¼ŃƒŃŽ Š°Ń€Ń…ŠøŃ‚ŠµŠŗŃ‚ŃƒŃ€Ńƒ, ŠŗŠ¾Ń‚Š¾Ń€Š°Ń ŠæŠ¾Š·Š²Š¾Š»ŃŠµŃ‚ вашему ŠæŃ€ŠøŠ»Š¾Š¶ŠµŠ½ŠøŃŽ или плагинам +ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŃŃ‚ŃŒ или Š“Š¾Š±Š°Š²Š»ŠµŠ½ŠøŃ его Š±Š°Š·Š¾Š²ŃƒŃŽ Ń„ŃƒŠ½ŠŗŃ†ŠøŠ¾Š½Š°Š»ŃŒŠ½Š¾ŃŃ‚ŃŒ. Bake ŠøŃŠæŠ¾Š»ŃŒŠ·ŃƒŠµŃ‚ ŃŠæŠµŃ†ŠøŠ°Š»ŃŒŠ½Ń‹Š¹ +класс, который ŠøŃŠæŠ¾Š»ŃŒŠ·ŃƒŠµŃ‚ механизм ŃˆŠ°Š±Š»Š¾Š½ŠøŠ·Š°Ń‚Š¾Ń€Š° `Twig `_. + +Š”Š¾Š±Ń‹Ń‚ŠøŃ Bake +============ + +Š’ качестве класса ŠæŃ€ŠµŠ“ŃŃ‚Š°Š²Š»ŠµŠ½ŠøŃ ``BakeView`` Š³ŠµŠ½ŠµŃ€ŠøŃ€ŃƒŠµŃ‚ те же ŃŠ¾Š±Ń‹Ń‚ŠøŃ, что Šø Š»ŃŽŠ±Š¾Š¹ Š“Ń€ŃƒŠ³Š¾Š¹ класс ŠæŃ€ŠµŠ“ŃŃ‚Š°Š²Š»ŠµŠ½ŠøŃ, +ŠæŠ»ŃŽŃ оГно Š“Š¾ŠæŠ¾Š»Š½ŠøŃ‚ŠµŠ»ŃŒŠ½Š¾Šµ событие инициализации. ŠžŠ“Š½Š°ŠŗŠ¾, в то Š²Ń€ŠµŠ¼Ń как классы станГартного ŠæŃ€ŠµŠ“ŃŃ‚Š°Š²Š»ŠµŠ½ŠøŃ ŠøŃŠæŠ¾Š»ŃŒŠ·ŃƒŃŽŃ‚ +префикс ŃŠ¾Š±Ń‹Ń‚ŠøŃ "View.", ``BakeView`` ŠøŃŠæŠ¾Š»ŃŒŠ·ŃƒŠµŃ‚ префикс ŃŠ¾Š±Ń‹Ń‚ŠøŃ "Bake.". + +Добытие initialize можно ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŃŒ Š“Š»Ń Š²Š½ŠµŃŠµŠ½ŠøŃ изменений, которые ŠæŃ€ŠøŠ¼ŠµŠ½ŃŃŽŃ‚ся ко всем 'испеченным' +вывоГам, например, чтобы Š“Š¾Š±Š°Š²ŠøŃ‚ŃŒ Š“Ń€ŃƒŠ³Š¾Š³Š¾ помощника в класс виГа bake, ŃŃ‚Š¾ событие может +ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŃŒ ŃŠ»ŠµŠ“ŃƒŃŽŃ‰ŠµŠµ:: + + on('Bake.initialize', function (Event $event) { + $view = $event->getSubject(); + + // Š’ моих ŃˆŠ°Š±Š»Š¾Š½Š°Ń… bake, Ń€Š°Š·Ń€ŠµŃˆŠøŃ‚ŃŒ использование MySpecial helper + $view->loadHelper('MySpecial', ['some' => 'config']); + + // И Š“Š¾Š±Š°Š²ŃŒŃ‚Šµ ŠæŠµŃ€ŠµŠ¼ŠµŠ½Š½ŃƒŃŽ $author, чтобы она всегГа была Š“Š¾ŃŃ‚ŃƒŠæŠ½Š° + $view->set('author', 'Andy'); + + }); + +Если вы хотите ŠøŠ·Š¼ŠµŠ½ŠøŃ‚ŃŒ Š²Ń‹ŠæŠµŃ‡ŠŗŃƒ ŠøŠ· Š“Ń€ŃƒŠ³Š¾Š³Š¾ плагина, Ń…Š¾Ń€Š¾ŃˆŠµŠ¹ иГеей Š±ŃƒŠ“ет - ŠæŠ¾Š¼ŠµŃŃ‚ŠøŃ‚ŃŒ +ŃŠ¾Š±Ń‹Ń‚ŠøŃ своего плагина в файл ``config/bootstrap.php``. + +Š”Š¾Š±Ń‹Ń‚ŠøŃ Bake Š¼Š¾Š³ŃƒŃ‚ Š±Ń‹Ń‚ŃŒ полезны Š“Š»Ń Š²Š½ŠµŃŠµŠ½ŠøŃ Š½ŠµŠ±Š¾Š»ŃŒŃˆŠøŃ… изменений в ŃŃƒŃ‰ŠµŃŃ‚Š²ŃƒŃŽŃ‰ŠøŠµ ŃˆŠ°Š±Š»Š¾Š½Ń‹. +ŠŠ°ŠæŃ€ŠøŠ¼ŠµŃ€, чтобы ŠøŠ·Š¼ŠµŠ½ŠøŃ‚ŃŒ имена переменных, ŠøŃŠæŠ¾Š»ŃŒŠ·ŃƒŠµŠ¼Ń‹Ń… Š“Š»Ń выпечки файлов контроллеров/шаблонов, +можно ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŃŒ ŠæŃ€Š¾ŃŠ»ŃƒŃˆŠøŠ²Š°ŃŽŃ‰ŃƒŃŽ Ń„ŃƒŠ½ŠŗŃ†ŠøŃŽ ``Bake.beforeRender``:: + + on('Bake.beforeRender', function (Event $event) { + $view = $event->getSubject(); + + // Š˜ŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŃŒ $rows Š“Š»Ń основной переменной Ганных Š“Š»Ń инГекса (index) + if ($view->get('pluralName')) { + $view->set('pluralName', 'rows'); + } + if ($view->get('pluralVar')) { + $view->set('pluralVar', 'rows'); + } + + // Š˜ŃŠæŠ¾Š»ŃŒŠ·ŃƒŠ¹Ń‚Šµ $theOne Š“Š»Ń основной переменной Ганных Š“Š»Ń просмотра/Ń€ŠµŠ“Š°ŠŗŃ‚ŠøŃ€Š¾Š²Š°Š½ŠøŃ (view/edit) + if ($view->get('singularName')) { + $view->set('singularName', 'theOne'); + } + if ($view->get('singularVar')) { + $view->set('singularVar', 'theOne'); + } + + }); + +Š’Ń‹ также можете ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŃŒ ŃŠ¾Š±Ń‹Ń‚ŠøŃ ``Bake.beforeRender`` Šø ``Bake.afterRender`` Š“Š»Ń +Š³ŠµŠ½ŠµŃ€ŠøŃ€Š¾Š²Š°Š½ŠøŃ специфичного файла. ŠŠ°ŠæŃ€ŠøŠ¼ŠµŃ€, если вы хотите Š“Š¾Š±Š°Š²ŠøŃ‚ŃŒ опреГеленные Š“ŠµŠ¹ŃŃ‚Š²ŠøŃ Š“Š»Ń +вашего UserController при генерации ŠøŠ· файла **Controller/controller.twig**, +вы можете ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŃŒ ŃŠ»ŠµŠ“ŃƒŃŽŃ‰ŠµŠµ событие:: + + on( + 'Bake.beforeRender.Controller.controller', + function (Event $event) { + $view = $event->getSubject(); + if ($view->viewVars['name'] == 'Users') { + // Гобавим Š“ŠµŠ¹ŃŃ‚Š²ŠøŃ вхоГа Šø выхоГа ŠøŠ· системы в контроллер ŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŠµŠ»ŠµŠ¹ + $view->viewVars['actions'] = [ + 'login', + 'logout', + 'index', + 'view', + 'add', + 'edit', + 'delete' + ]; + } + } + ); + +ŠŸŃ€Šø просмотре ŠæŃ€Š¾ŃŠ»ŃƒŃˆŠøŠ²Š°Ń‚елей событий Š“Š»Ń конкретных шаблонов выпечки вы можете ŃƒŠæŃ€Š¾ŃŃ‚ŠøŃ‚ŃŒ +Š²Ń‹ŠæŠµŃ‡ŠŗŃƒ ŃŠ²ŃŠ·Š°Š½Š½Š¾Š¹ логики событий Šø Š¾Š±ŠµŃŠæŠµŃ‡ŠøŃ‚ŃŒ обратные вызовы, которые легче Ń‚ŠµŃŃ‚ŠøŃ€Š¾Š²Š°Ń‚ŃŒ. + +Динтаксис шаблона выпечки +========================= + +Файлы шаблонов Bake ŠøŃŠæŠ¾Š»ŃŒŠ·ŃƒŃŽŃ‚ синтаксис ŃˆŠ°Š±Š»Š¾Š½ŠøŠ·Š°Ń‚Š¾Ń€Š° `Twig `__. + +ŠžŠ“ŠøŠ½ ŠøŠ· способов ŃƒŠ²ŠøŠ“ŠµŃ‚ŃŒ/ŠæŠ¾Š½ŃŃ‚ŃŒ, как Ń€Š°Š±Š¾Ń‚Š°ŃŽŃ‚ ŃˆŠ°Š±Š»Š¾Š½Ń‹ выпечки, особенно при попытке +ŠøŠ·Š¼ŠµŠ½ŠøŃ‚ŃŒ файлы шаблонов выпечки, ŃŃ‚Š¾ - ŠøŃŠæŠµŃ‡ŃŒ класс Šø ŃŃ€Š°Š²Š½ŠøŃ‚ŃŒ ŠøŃŠæŠ¾Š»ŃŒŠ·ŃƒŠµŠ¼Ń‹Š¹ шаблон +с ŠæŃ€ŠµŠ“Š²Š°Ń€ŠøŃ‚ŠµŠ»ŃŒŠ½Š¾ обработанным файлом шаблона, который Š¾ŃŃ‚Š°Ń‘Ń‚ŃŃ в приложении в папке +**tmp/bake**. + +Так, например, при выпечке такой оболочки: + +.. code-block:: bash + + bin/cake bake shell Foo + +Š˜ŃŠæŠ¾Š»ŃŒŠ·ŃƒŠµŠ¼Ń‹Š¹ шаблон (**vendor/cakephp/bake/src/Template/Bake/Shell/shell.twig**) +Š±ŃƒŠ“ŠµŃ‚ Š²Ń‹Š³Š»ŃŠ“ŠµŃ‚ŃŒ так:: + + `` Bake шаблон Š·Š°ŠŗŃ€Ń‹Š²Š°ŃŽŃ‰ŠµŠ³Š¾ тега php + * ``<%=`` Bake шаблон php короткого php тега echo + * ``<%-`` Bake шаблон php Š¾Ń‚ŠŗŃ€Ń‹Ń‚ŠøŃ тега, ŃƒŠ“Š°Š»ŃŃŽŃ‰ŠµŠ³Š¾ Š»ŃŽŠ±Ń‹Šµ ввеГённые пробелы переГ тегом + * ``-%>`` Bake шаблон php Š·Š°ŠŗŃ€Ń‹Ń‚ŠøŃ тега, Š»ŃŽŠ±Ń‹Šµ ввеГённые пробелы после тега + +.. _creating-a-bake-theme: + +ДозГание темы Bake +================== + +Если вы хотите ŠøŠ·Š¼ŠµŠ½ŠøŃ‚ŃŒ Ń€ŠµŠ·ŃƒŠ»ŃŒŃ‚Š°Ń‚, ŠæŠ¾Š»ŃƒŃ‡ŠµŠ½Š½Ń‹Š¹ команГой "bake", вы можете +ŃŠ¾Š·Š“Š°Ń‚ŃŒ ŃŠ²Š¾ŃŽ ŃŠ¾Š±ŃŃ‚Š²ŠµŠ½Š½ŃƒŃŽ Ń‚ŠµŠ¼Ńƒ('theme') Š“Š»Ń "bake", ŠŗŠ¾Ń‚Š¾Ń€Š°Ń позволит вам Š·Š°Š¼ŠµŠ½ŠøŃ‚ŃŒ некоторые или все +ŃˆŠ°Š±Š»Š¾Š½Ń‹, которые испекает bake. Š›ŃƒŃ‡ŃˆŠµ всего ŃŠ“ŠµŠ»Š°Ń‚ŃŒ ŃŃ‚Š¾ так: + +#. Š’Ń‹ŠæŠµŃ‡ŃŒ новый плагин. Š˜Š¼Ń плагина - ŃŃ‚Š¾ название темы 'bake' +#. Š”Š¾Š·Š“Š°Ń‚ŃŒ Š½Š¾Š²ŃƒŃŽ Š“ŠøŃ€ŠµŃ‚ŠŗŠ¾Ń€ŠøŃŽ **plugins/[name]/src/Template/Bake/Template/**. +#. Š”ŠŗŠ¾ŠæŠøŃ€ŃƒŠ¹Ń‚Šµ Š»ŃŽŠ±Ń‹Šµ ŃˆŠ°Š±Š»Š¾Š½Ń‹, которые вы хотите ŠæŠµŃ€ŠµŠ¾ŠæŃ€ŠµŠ“ŠµŠ»ŠøŃ‚ŃŒ + **vendor/cakephp/bake/src/Template/Bake/Template** Š“Š»Ń ŃŠ¾ŠæŠ¾ŃŃ‚Š°Š²Š»ŠµŠ½ŠøŃ файлов с вашим плагином. +#. ŠŸŃ€Šø запуске выпечки ŠøŃŠæŠ¾Š»ŃŒŠ·ŃƒŠ¹Ń‚е параметр ``--theme``, чтобы ŃƒŠŗŠ°Š·Š°Ń‚ŃŒ Ń‚ŠµŠ¼Ńƒ выпечки ŠŗŠ¾Ń‚Š¾Ń€ŃƒŃŽ вы + хотите ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŃŒ. Чтобы ŠøŠ·Š±ŠµŠ¶Š°Ń‚ŃŒ необхоГимости ŃƒŠŗŠ°Š·Ń‹Š²Š°Ń‚ŃŒ ŃŃ‚Š¾Ń‚ параметр в кажГом вызове, вы также можете + Š½Š°ŃŃ‚Ń€Š¾ŠøŃ‚ŃŒ ŃŠ²Š¾ŃŽ Ń‚ŠµŠ¼Ńƒ в качестве темы по ŃƒŠ¼Š¾Š»Ń‡Š°Š½ŠøŃŽ:: + + Test->classSuffixes[$this->name()])) { + $this->Test->classSuffixes[$this->name()] = 'Foo'; + } + + $name = ucfirst($this->name()); + if (!isset($this->Test->classTypes[$name])) { + $this->Test->classTypes[$name] = 'Foo'; + } + + return parent::bakeTest($className); + } + +* **Š”ŃƒŃ„Ń„ŠøŠŗŃ класса** Š±ŃƒŠ“ŠµŃ‚ Гобавлен Šŗ имени, указанному в вашем вызове ``bake``. + Š’ ŠæŃ€ŠµŠ“Ń‹Š“ŃƒŃ‰ŠµŠ¼ примере он созГал бы файл ``ExampleFooTest.php``. + +* **Тип файла** Š±ŃƒŠ“ŠµŃ‚ ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŃŒ пространство поГ-пространство имён(sub-namespace), которое привеГёт Šŗ Ń„Š°Š¹Š»Ńƒ (Š¾Ń‚Š½Š¾ŃŠøŃ‚ŠµŠ»ŃŒŠ½Š¾ ŠæŃ€ŠøŠ»Š¾Š¶ŠµŠ½ŠøŃ или ŠæŠ¾Š“ŠŗŠ»ŃŽŃ‡Š°ŠµŠ¼Š¾Š³Š¾ Š¼Š¾Š“ŃƒŠ»Ń). Š’ ŠæŃ€ŠµŠ“Ń‹Š“ŃƒŃ‰ŠµŠ¼ примере, он созГаст ваш тест с пространством имен ``App\Test\TestCase\Foo``. + +.. meta:: + :title lang=ru: Š Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŠµ возможностей Bake + :keywords lang=ru: интерфейс команГной строки, разработка, выпечка, синтаксис шаблона выпечки, твинг, метки erb, процентные теги diff --git a/app/vendor/cakephp/bake/docs/ru/index.rst b/app/vendor/cakephp/bake/docs/ru/index.rst new file mode 100644 index 000000000..0b9c1bc80 --- /dev/null +++ b/app/vendor/cakephp/bake/docs/ru/index.rst @@ -0,0 +1,24 @@ +Консоль Bake +############ + +Bake консоль CakePHP - ŃŃ‚Š¾ еще оГин ŠøŠ½ŃŃ‚Ń€ŃƒŠ¼ŠµŠ½Ń‚ Š“Š»Ń быстрой разработки на фреймворке CakePHP. +Консоль Bake может ŃŠ¾Š·Š“Š°Ń‚ŃŒ Š»ŃŽŠ±Š¾Š¹ ŠøŠ· базовых компонентов или все ŃŃ€Š°Š·Ńƒ: models, +behaviors, views, helpers, controllers, components, test cases, fixtures Šø plugins. +Š ŠµŃ‡ŃŒ иГет не Ń‚Š¾Š»ŃŒŠŗŠ¾ о каркасе ŠæŃ€ŠøŠ»Š¾Š¶ŠµŠ½ŠøŃ: Bake консоль созГает ŠæŠ¾Š»Š½Š¾ŃŃ‚ŃŒŃŽ Ń„ŃƒŠ½ŠŗŃ†ŠøŠ¾Š½ŠøŃ€ŃƒŃŽŃ‰ŠµŠµ приложение всего за ŠæŠ°Ń€Ńƒ Š¼ŠøŠ½ŃƒŃ‚. + +Bake ŃŃ‚Š¾ естественный шаг Š“Š»Ń статической генерации коГа. + +Установка +========= + +ŠŸŠµŃ€ŠµŠ“ тем, как ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŃŒ Bake, ŃƒŠ±ŠµŠ“ŠøŃ‚ŠµŃŃŒ, что он ŃƒŃŃ‚Š°Š½Š¾Š²Š»ŠµŠ½ в вашем приложении. +Bake ŃŃ‚Š¾ Š¾Ń‚Š“ŠµŠ»ŃŒŠ½Ń‹Š¹ плагин Šø вы можете ŃƒŃŃ‚Š°Š½Š¾Š²ŠøŃ‚ŃŒ его с ŠæŠ¾Š¼Š¾Ń‰ŃŒŃŽ Composer:: + + composer require --dev cakephp/bake:~1.0 + +КоманГа Š²Ń‹ŃˆŠµ ŃƒŃŃ‚Š°Š½Š¾Š²ŠøŃ‚ Bake в зависимости от разработки. +Это значит, что Bake не Š±ŃƒŠ“ет ŃƒŃŃ‚Š°Š½Š¾Š²Š»ŠµŠ½, когГа вы Гелаете Геплой на ŠæŃ€Š¾Š“Š°ŠŗŃˆŠ½ сервер. + +.. meta:: + :title lang=ru: Консоль Bake + :keywords lang=ru: интерфейс команГной строки,разработка,bake view, bake template syntax,erb tags,asp tags,percent tags diff --git a/app/vendor/cakephp/bake/docs/ru/usage.rst b/app/vendor/cakephp/bake/docs/ru/usage.rst new file mode 100644 index 000000000..8cfd72b85 --- /dev/null +++ b/app/vendor/cakephp/bake/docs/ru/usage.rst @@ -0,0 +1,131 @@ +Š“ŠµŠ½ŠµŃ€Š°Ń†ŠøŃ коГа с ŠæŠ¾Š¼Š¾Ń‰ŃŒŃŽ Bake +############################# + +Консоль cake Š·Š°ŠæŃƒŃŠŗŠ°ŠµŃ‚ŃŃ с использованием PHP CLI (интерфейса команГной строки). +Если у вас возникли проблемы с запуском скрипта, ŃƒŠ±ŠµŠ“ŠøŃ‚ŠµŃŃŒ, что: + +#. Š£ вас ŃƒŃŃ‚Š°Š½Š¾Š²Š»ŠµŠ½ PHP CLI Šø что у него ŠµŃŃ‚ŃŒ ŃŠ¾Š¾Ń‚Š²ŠµŃ‚ŃŃ‚Š²ŃƒŃŽŃ‰ŠøŠµ Š²ŠŗŠ»ŃŽŃ‡Ń‘Š½Š½Ń‹Šµ моГули + (например: MySQL, intl). +#. Š£ ŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŠµŠ»ŠµŠ¹ также Š¼Š¾Š³ŃƒŃ‚ Š±Ń‹Ń‚ŃŒ проблемы, если хост базы Ганных ŃŠ²Š»ŃŠµŃ‚ŃŃ + 'localhost' вмеcто ŃŃ‚Š¾Š³Š¾ можно ŠæŠ¾ŠæŃ€Š¾Š±Š¾Š²Š°Ń‚ŃŒ '127.0.0.1', поскольку localhost + может Š²Ń‹Š·Š²Š°Ń‚ŃŒ проблемы с PHP CLI. +#. Š’ зависимости от того, как настроен ваш ŠŗŠ¾Š¼ŠæŃŒŃŽŃ‚ŠµŃ€, вам может ŠæŠ¾Ń‚Ń€ŠµŠ±Š¾Š²Š°Ń‚ŃŒŃŃ + ŃƒŃŃ‚Š°Š½Š¾Š²ŠøŃ‚ŃŒ права Š²Ń‹ŠæŠ¾Š»Š½ŠµŠ½ŠøŃ на скрипт bash, чтобы Š²Ń‹Š·Š²Š°Ń‚ŃŒ его, ŠøŃŠæŠ¾Š»ŃŒŠ·ŃƒŃ + ``bin/cake bake``. + +ŠŸŠµŃ€ŠµŠ“ запуском bake вы Голжны ŃƒŠ±ŠµŠ“ŠøŃ‚ŃŒŃŃ, что у вас ŠµŃŃ‚ŃŒ Ń…Š¾Ń‚Ń бы оГна база Ганных Šø +соеГинение настроено. + +ŠŸŃ€Šø запуске без Š°Ń€Š³ŃƒŠ¼ŠµŠ½Ń‚ов ``bin/cake bake`` вывоГит список Š“Š¾ŃŃ‚ŃƒŠæŠ½Ń‹Ń… +заГаний. Š’Ń‹ Голжны ŃƒŠ²ŠøŠ“ŠµŃ‚ŃŒ что-то вроГе:: + + $ bin/cake bake + + Welcome to CakePHP v3.4.6 Console + --------------------------------------------------------------- + App : src + Path: /var/www/cakephp.dev/src/ + PHP : 5.6.20 + --------------------------------------------------------------- + The following commands can be used to generate skeleton code for your application. + + Available bake commands: + + - all + - behavior + - cell + - component + - controller + - fixture + - form + - helper + - mailer + - migration + - migration_diff + - migration_snapshot + - model + - plugin + - seed + - shell + - shell_helper + - task + - template + - test + + By using `cake bake [name]` you can invoke a specific bake task. + +Š’Ń‹ можете ŠæŠ¾Š»ŃƒŃ‡ŠøŃ‚ŃŒ больше Š“Š¾ŠæŠ¾Š»Š½ŠøŃ‚ŠµŠ»ŃŒŠ½Š¾Š¹ информации о том, что Гелает ŠŗŠ°Š¶Š“Š°Ń заГача, Šø какие параметры +Š“Š¾ŃŃ‚ŃƒŠæŠ½Ń‹, если ŠøŃŠæŠ¾Š»ŃŒŠ·ŃƒŠµŃ‚е ŠŗŠ»ŃŽŃ‡ ``--help``:: + + $ bin/cake bake --help + + Welcome to CakePHP v3.4.6 Console + --------------------------------------------------------------- + App : src + Path: /var/www/cakephp.dev/src/ + PHP : 5.6.20 + --------------------------------------------------------------- + The Bake script generates controllers, models and template files for + your application. If run with no command line arguments, Bake guides the + user through the class creation process. You can customize the + generation process by telling Bake where different parts of your + application are using command line arguments. + + Usage: + cake bake.bake [subcommand] [options] + + Subcommands: + + all Bake a complete MVC skeleton. + behavior Bake a behavior class file. + cell Bake a cell class file. + component Bake a component class file. + controller Bake a controller skeleton. + fixture Generate fixtures for use with the test suite. You + can use `bake fixture all` to bake all fixtures. + form Bake a form class file. + helper Bake a helper class file. + mailer Bake a mailer class file. + migration Bake migration class. + migration_diff Bake migration class. + migration_snapshot Bake migration snapshot class. + model Bake table and entity classes. + plugin Create the directory structure, AppController class + and testing setup for a new plugin. Can create + plugins in any of your bootstrapped plugin paths. + seed Bake seed class. + shell Bake a shell class file. + shell_helper Bake a shell_helper class file. + task Bake a task class file. + template Bake views for a controller, using built-in or + custom templates. + test Bake test case skeletons for classes. + + To see help on a subcommand use `cake bake.bake [subcommand] --help` + + Options: + + --connection, -c Database connection to use in conjunction with `bake + all`. (default: default) + --everything Bake a complete MVC skeleton, using all the available + tables. Usage: "bake all --everything" + --force, -f Force overwriting existing files without prompting. + --help, -h Display this help. + --plugin, -p Plugin to bake into. + --prefix Prefix to bake controllers and templates into. + --quiet, -q Enable quiet output. + --tablePrefix Table prefix to be used in models. + --theme, -t The theme to use when baking code. (choices: + Bake|Migrations) + --verbose, -v Enable verbose output. + +Темы Bake +========= + +ŠŸŠ°Ń€Š°Š¼ŠµŃ‚Ń€ темы ŃŠ²Š»ŃŠµŃ‚ŃŃ общим Š“Š»Ń всех команГ bake, так же bake ŠæŠ¾Š·Š²Š¾Š»ŃŠµŃ‚ ŠøŠ·Š¼ŠµŠ½ŃŃ‚ŃŒ +файлы шаблонов, ŠøŃŠæŠ¾Š»ŃŒŠ·ŃƒŠµŠ¼Ń‹Šµ при 'выпечке'. Чтобы ŃŠ¾Š·Š“Š°Ń‚ŃŒ свои собственные ŃˆŠ°Š±Š»Š¾Š½Ń‹ см. +:ref:`Š“Š¾ŠŗŃƒŠ¼ŠµŠ½Ń‚Š°Ń†ŠøŃ по ŃŠ¾Š·Š“Š°Š½ŠøŃŽ темы`. + +.. meta:: + :title lang=ru: Š“ŠµŠ½ŠµŃ€Š°Ń†ŠøŃ коГа с ŠæŠ¾Š¼Š¾Ń‰ŃŒŃŽ Bake + :keywords lang=en: command line interface,functional application,database,database configuration,bash script,basic ingredients,project,model,path path,code generation,scaffolding,windows users,configuration file,few minutes,config,iew,shell,models,running,mysql diff --git a/app/vendor/cakephp/bake/phpcs.xml.dist b/app/vendor/cakephp/bake/phpcs.xml.dist new file mode 100644 index 000000000..ce02df237 --- /dev/null +++ b/app/vendor/cakephp/bake/phpcs.xml.dist @@ -0,0 +1,8 @@ + + + + + + + */comparisons/* + diff --git a/app/vendor/cakephp/bake/phpstan.neon b/app/vendor/cakephp/bake/phpstan.neon new file mode 100644 index 000000000..4decabc09 --- /dev/null +++ b/app/vendor/cakephp/bake/phpstan.neon @@ -0,0 +1,7 @@ +parameters: + level: 6 + checkMissingIterableValueType: false + paths: + - src + bootstrapFiles: + - tests/bootstrap.php diff --git a/app/vendor/cakephp/bake/psalm-baseline.xml b/app/vendor/cakephp/bake/psalm-baseline.xml new file mode 100644 index 000000000..a49882bc1 --- /dev/null +++ b/app/vendor/cakephp/bake/psalm-baseline.xml @@ -0,0 +1,19 @@ + + + + + new Filesystem() + + + findRecursive + + + + + new Filesystem() + + + find + + + diff --git a/app/vendor/cakephp/bake/psalm.xml b/app/vendor/cakephp/bake/psalm.xml new file mode 100644 index 000000000..de0149164 --- /dev/null +++ b/app/vendor/cakephp/bake/psalm.xml @@ -0,0 +1,18 @@ + + + + + + + + + diff --git a/app/vendor/cakephp/bake/src/Command/AllCommand.php b/app/vendor/cakephp/bake/src/Command/AllCommand.php new file mode 100644 index 000000000..894347549 --- /dev/null +++ b/app/vendor/cakephp/bake/src/Command/AllCommand.php @@ -0,0 +1,123 @@ +_setCommonOptions($parser); + + $parser = $parser->setDescription( + 'Generate the model, controller, template, tests and fixture for a table.' + )->addArgument('name', [ + 'help' => 'Name of the table to generate code for.', + ])->addOption('everything', [ + 'help' => 'Generate code for all tables.', + 'default' => false, + 'boolean' => true, + ])->addOption('prefix', [ + 'help' => 'The namespace prefix to use.', + 'default' => false, + ]); + + return $parser; + } + + /** + * Execute the command. + * + * @param \Cake\Console\Arguments $args The command arguments. + * @param \Cake\Console\ConsoleIo $io The console io + * @return int|null The exit code or null for success + */ + public function execute(Arguments $args, ConsoleIo $io): ?int + { + $this->extractCommonProperties($args); + $name = $args->getArgument('name') ?? ''; + $name = $this->_getName($name); + + $io->out('Bake All'); + $io->hr(); + + /** @var \Cake\Database\Connection $connection */ + $connection = ConnectionManager::get($this->connection); + $scanner = new TableScanner($connection); + if (empty($name) && !$args->getOption('everything')) { + $io->out('Choose a table to generate from the following:'); + foreach ($scanner->listUnskipped() as $table) { + $io->out('- ' . $this->_camelize($table)); + } + + return static::CODE_SUCCESS; + } + if ($args->getOption('everything')) { + $tables = $scanner->listUnskipped(); + } else { + $tables = [$name]; + } + + foreach ($this->commands as $commandName) { + /** @var \Cake\Command\Command $command */ + $command = new $commandName(); + + $options = $args->getOptions(); + if ( + $args->hasOption('prefix') && + !($command instanceof ControllerCommand) && + !($command instanceof TemplateCommand) + ) { + unset($options['prefix']); + } + + foreach ($tables as $table) { + $subArgs = new Arguments([$table], $options, ['name']); + $command->execute($subArgs, $io); + } + } + + $io->out('Bake All complete.', 1, ConsoleIo::QUIET); + + return static::CODE_SUCCESS; + } +} diff --git a/app/vendor/cakephp/bake/src/Command/BakeCommand.php b/app/vendor/cakephp/bake/src/Command/BakeCommand.php new file mode 100644 index 000000000..24f23da69 --- /dev/null +++ b/app/vendor/cakephp/bake/src/Command/BakeCommand.php @@ -0,0 +1,167 @@ +plugin = $plugin; + } + + return $name; + } + + /** + * Get the prefix name. + * + * Handles camelcasing each namespace in the prefix path. + * + * @param \Cake\Console\Arguments $args Arguments instance to read the prefix option from. + * @return string The inflected prefix path. + */ + protected function getPrefix(Arguments $args): string + { + $prefix = $args->getOption('prefix'); + if (!$prefix) { + return ''; + } + $parts = explode('/', $prefix); + + return implode('/', array_map([$this, '_camelize'], $parts)); + } + + /** + * Gets the path for output. Checks the plugin property + * and returns the correct path. + * + * @param \Cake\Console\Arguments $args Arguments instance to read the prefix option from. + * @return string Path to output. + */ + public function getPath(Arguments $args): string + { + $path = APP . $this->pathFragment; + if ($this->plugin) { + $path = $this->_pluginPath($this->plugin) . 'src/' . $this->pathFragment; + } + $prefix = $this->getPrefix($args); + if ($prefix) { + $path .= $prefix . DIRECTORY_SEPARATOR; + } + + return str_replace('/', DIRECTORY_SEPARATOR, $path); + } + + /** + * Gets the path to the template path for the application or plugin. + * + * @param \Cake\Console\Arguments $args Arguments instance to read the prefix option from. + * @param string|null $container The container directory in the templates directory. + * @return string Path to output. + */ + public function getTemplatePath(Arguments $args, ?string $container = null): string + { + $paths = (array)Configure::read('App.paths.templates'); + if (empty($paths)) { + throw new InvalidArgumentException( + 'Could not read template paths. ' . + 'Ensure `App.paths.templates` is defined in your application configuration.' + ); + } + $path = $paths[0]; + if ($this->plugin) { + $path = $this->_pluginPath($this->plugin) . 'templates' . DIRECTORY_SEPARATOR; + } + if ($container) { + $path .= $container . DIRECTORY_SEPARATOR; + } + $prefix = $this->getPrefix($args); + if ($prefix) { + $path .= $prefix . DIRECTORY_SEPARATOR; + } + + return str_replace('/', DIRECTORY_SEPARATOR, $path); + } + + /** + * Delete empty file in a given path + * + * @param string $path Path to folder which contains 'empty' file. + * @param \Cake\Console\ConsoleIo $io ConsoleIo to delete file with. + * @return void + */ + protected function deleteEmptyFile(string $path, ConsoleIo $io): void + { + if (file_exists($path)) { + unlink($path); + $io->out(sprintf('Deleted `%s`', $path), 1, ConsoleIo::QUIET); + } + } +} diff --git a/app/vendor/cakephp/bake/src/Command/BehaviorCommand.php b/app/vendor/cakephp/bake/src/Command/BehaviorCommand.php new file mode 100644 index 000000000..e5b5e852e --- /dev/null +++ b/app/vendor/cakephp/bake/src/Command/BehaviorCommand.php @@ -0,0 +1,54 @@ + + */ + public function templateData(Arguments $arguments): array + { + $prefix = $this->getPrefix($arguments); + if ($prefix) { + $prefix = '\\' . str_replace('/', '\\', $prefix); + } + + $namespace = Configure::read('App.namespace'); + if ($this->plugin) { + $namespace = $this->_pluginNamespace($this->plugin); + } + + return compact('namespace', 'prefix'); + } + + /** + * Bake the Cell class and template file. + * + * @param string $name The name of the cell to make. + * @param \Cake\Console\Arguments $args The console arguments + * @param \Cake\Console\ConsoleIo $io The console io + * @return void + */ + public function bake(string $name, Arguments $args, ConsoleIo $io): void + { + $this->bakeTemplate($name, $args, $io); + + parent::bake($name, $args, $io); + } + + /** + * Bake an empty file for a cell. + * + * @param string $name The name of the cell a template is needed for. + * @param \Cake\Console\Arguments $args The console arguments + * @param \Cake\Console\ConsoleIo $io The console io + * @return void + */ + protected function bakeTemplate(string $name, Arguments $args, ConsoleIo $io): void + { + $path = $this->getTemplatePath($args, 'cell'); + $path .= implode(DS, [$name, 'display.php']); + + $io->createFile($path, '', $args->getOption('force')); + } + + /** + * Gets the option parser instance and configures it. + * + * @param \Cake\Console\ConsoleOptionParser $parser Parser instance + * @return \Cake\Console\ConsoleOptionParser + */ + public function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser + { + $parser = parent::buildOptionParser($parser); + $parser->addOption('prefix', [ + 'help' => 'The namespace prefix to use.', + ]); + + return $parser; + } +} diff --git a/app/vendor/cakephp/bake/src/Command/CommandCommand.php b/app/vendor/cakephp/bake/src/Command/CommandCommand.php new file mode 100644 index 000000000..dfca1a419 --- /dev/null +++ b/app/vendor/cakephp/bake/src/Command/CommandCommand.php @@ -0,0 +1,54 @@ +controllerCommand = new ControllerCommand(); + } + + /** + * Execute the command. + * + * @param \Cake\Console\Arguments $args The command arguments. + * @param \Cake\Console\ConsoleIo $io The console io + * @return int|null The exit code or null for success + */ + public function execute(Arguments $args, ConsoleIo $io): ?int + { + $this->extractCommonProperties($args); + + /** @var \Cake\Database\Connection $connection */ + $connection = ConnectionManager::get($this->connection); + $scanner = new TableScanner($connection); + foreach ($scanner->listUnskipped() as $table) { + $this->getTableLocator()->clear(); + $controllerArgs = new Arguments([$table], $args->getOptions(), ['name']); + $this->controllerCommand->execute($controllerArgs, $io); + } + + return static::CODE_SUCCESS; + } + + /** + * Gets the option parser instance and configures it. + * + * @param \Cake\Console\ConsoleOptionParser $parser The console option parser + * @return \Cake\Console\ConsoleOptionParser + */ + public function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser + { + $parser = $this->controllerCommand->buildOptionParser($parser); + $parser + ->setDescription('Bake all controller files with tests.') + ->setEpilog(''); + + return $parser; + } +} diff --git a/app/vendor/cakephp/bake/src/Command/ControllerCommand.php b/app/vendor/cakephp/bake/src/Command/ControllerCommand.php new file mode 100644 index 000000000..d83e43969 --- /dev/null +++ b/app/vendor/cakephp/bake/src/Command/ControllerCommand.php @@ -0,0 +1,279 @@ +extractCommonProperties($args); + $name = $args->getArgument('name') ?? ''; + $name = $this->_getName($name); + + if (empty($name)) { + /** @var \Cake\Database\Connection $connection */ + $connection = ConnectionManager::get($this->connection); + $scanner = new TableScanner($connection); + $io->out('Possible controllers based on your current database:'); + foreach ($scanner->listUnskipped() as $table) { + $io->out('- ' . $this->_camelize($table)); + } + + return static::CODE_SUCCESS; + } + + $controller = $this->_camelize($name); + $this->bake($controller, $args, $io); + + return static::CODE_SUCCESS; + } + + /** + * Assembles and writes a Controller file + * + * @param string $controllerName Controller name already pluralized and correctly cased. + * @param \Cake\Console\Arguments $args The console arguments + * @param \Cake\Console\ConsoleIo $io The console io + * @return void + */ + public function bake(string $controllerName, Arguments $args, ConsoleIo $io): void + { + $io->quiet(sprintf('Baking controller class for %s...', $controllerName)); + + $actions = []; + if (!$args->getOption('no-actions') && !$args->getOption('actions')) { + $actions = ['index', 'view', 'add', 'edit', 'delete']; + } + if ($args->getOption('actions')) { + $actions = array_map('trim', explode(',', $args->getOption('actions'))); + $actions = array_filter($actions); + } + + $helpers = $this->getHelpers($args); + $components = $this->getComponents($args); + + $prefix = $this->getPrefix($args); + if ($prefix) { + $prefix = '\\' . str_replace('/', '\\', $prefix); + } + + // Controllers default to importing AppController from `App` + $baseNamespace = $namespace = Configure::read('App.namespace'); + if ($this->plugin) { + $namespace = $this->_pluginNamespace($this->plugin); + } + // If the plugin has an AppController other plugin controllers + // should inherit from it. + if ($this->plugin && class_exists("{$namespace}\Controller\AppController")) { + $baseNamespace = $namespace; + } + + $currentModelName = $controllerName; + $plugin = $this->plugin; + if ($plugin) { + $plugin .= '.'; + } + + if ($this->getTableLocator()->exists($plugin . $currentModelName)) { + $modelObj = $this->getTableLocator()->get($plugin . $currentModelName); + } else { + $modelObj = $this->getTableLocator()->get($plugin . $currentModelName, [ + 'connectionName' => $this->connection, + ]); + } + + $pluralName = $this->_variableName($currentModelName); + $singularName = $this->_singularName($currentModelName); + $singularHumanName = $this->_singularHumanName($controllerName); + $pluralHumanName = $this->_variableName($controllerName); + + $defaultModel = sprintf('%s\Model\Table\%sTable', $namespace, $controllerName); + if (!class_exists($defaultModel)) { + $defaultModel = null; + } + $entityClassName = $this->_entityName($modelObj->getAlias()); + + $data = compact( + 'actions', + 'components', + 'currentModelName', + 'defaultModel', + 'entityClassName', + 'helpers', + 'modelObj', + 'namespace', + 'baseNamespace', + 'plugin', + 'pluralHumanName', + 'pluralName', + 'prefix', + 'singularHumanName', + 'singularName' + ); + $data['name'] = $controllerName; + + $this->bakeController($controllerName, $data, $args, $io); + $this->bakeTest($controllerName, $args, $io); + } + + /** + * Generate the controller code + * + * @param string $controllerName The name of the controller. + * @param array $data The data to turn into code. + * @param \Cake\Console\Arguments $args The console args + * @param \Cake\Console\ConsoleIo $io The console io + * @return void + */ + public function bakeController(string $controllerName, array $data, Arguments $args, ConsoleIo $io): void + { + $data += [ + 'name' => null, + 'namespace' => null, + 'prefix' => null, + 'actions' => null, + 'helpers' => null, + 'components' => null, + 'plugin' => null, + 'pluginPath' => null, + ]; + + $renderer = new TemplateRenderer($this->theme); + $renderer->set($data); + + $contents = $renderer->generate('Bake.Controller/controller'); + + $path = $this->getPath($args); + $filename = $path . $controllerName . 'Controller.php'; + $io->createFile($filename, $contents, $args->getOption('force')); + } + + /** + * Assembles and writes a unit test file + * + * @param string $className Controller class name + * @param \Cake\Console\Arguments $args The console arguments + * @param \Cake\Console\ConsoleIo $io The console io + * @return void + */ + public function bakeTest(string $className, Arguments $args, ConsoleIo $io): void + { + if ($args->getOption('no-test')) { + return; + } + $test = new TestCommand(); + $testArgs = new Arguments( + ['controller', $className], + $args->getOptions(), + ['type', 'name'] + ); + $test->execute($testArgs, $io); + } + + /** + * Get the list of components for the controller. + * + * @param \Cake\Console\Arguments $args The console arguments + * @return string[] + */ + public function getComponents(Arguments $args): array + { + $components = []; + if ($args->getOption('components')) { + $components = explode(',', $args->getOption('components')); + $components = array_values(array_filter(array_map('trim', $components))); + } + + return $components; + } + + /** + * Get the list of helpers for the controller. + * + * @param \Cake\Console\Arguments $args The console arguments + * @return string[] + */ + public function getHelpers(Arguments $args): array + { + $helpers = []; + if ($args->getOption('helpers')) { + $helpers = explode(',', $args->getOption('helpers')); + $helpers = array_values(array_filter(array_map('trim', $helpers))); + } + + return $helpers; + } + + /** + * Gets the option parser instance and configures it. + * + * @param \Cake\Console\ConsoleOptionParser $parser The console option parser + * @return \Cake\Console\ConsoleOptionParser + */ + public function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser + { + $parser = $this->_setCommonOptions($parser); + $parser->setDescription( + 'Bake a controller skeleton.' + )->addArgument('name', [ + 'help' => 'Name of the controller to bake (without the `Controller` suffix). ' . + 'You can use Plugin.name to bake controllers into plugins.', + ])->addOption('components', [ + 'help' => 'The comma separated list of components to use.', + ])->addOption('helpers', [ + 'help' => 'The comma separated list of helpers to use.', + ])->addOption('prefix', [ + 'help' => 'The namespace/routing prefix to use.', + ])->addOption('actions', [ + 'help' => 'The comma separated list of actions to generate. ' . + 'You can include custom methods provided by your template set here.', + ])->addOption('no-test', [ + 'boolean' => true, + 'help' => 'Do not generate a test skeleton.', + ])->addOption('no-actions', [ + 'boolean' => true, + 'help' => 'Do not generate basic CRUD action methods.', + ]); + + return $parser; + } +} diff --git a/app/vendor/cakephp/bake/src/Command/EntryCommand.php b/app/vendor/cakephp/bake/src/Command/EntryCommand.php new file mode 100644 index 000000000..ba7b51558 --- /dev/null +++ b/app/vendor/cakephp/bake/src/Command/EntryCommand.php @@ -0,0 +1,231 @@ +commands = $commands; + } + + /** + * Run the command. + * + * Override the run() method so that we can splice in dynamic + * subcommand handling for legacy tasks. + * + * @param array $argv Arguments from the CLI environment. + * @param \Cake\Console\ConsoleIo $io The console io + * @return int|null Exit code or null for success. + */ + public function run(array $argv, ConsoleIo $io): ?int + { + $this->initialize(); + + $parser = $this->getOptionParser(); + try { + [$options, $arguments] = $parser->parse($argv); + $args = new Arguments( + $arguments, + $options, + $parser->argumentNames() + ); + } catch (ConsoleException $e) { + $io->err('Error: ' . $e->getMessage()); + + return static::CODE_ERROR; + } + $this->setOutputLevel($args, $io); + + // This is the variance from Command::run() + if (!$args->getArgumentAt(0) && $args->getOption('help')) { + $this->executeCommand($this->help, [], $io); + + return static::CODE_SUCCESS; + } + + return $this->execute($args, $io); + } + + /** + * Execute the command. + * + * This command acts as a catch-all for legacy tasks that may + * be defined in the application or plugins. + * + * @param \Cake\Console\Arguments $args The command arguments. + * @param \Cake\Console\ConsoleIo $io The console io + * @return int|null The exit code or null for success + */ + public function execute(Arguments $args, ConsoleIo $io): ?int + { + if ($args->hasArgumentAt(0)) { + $name = $args->getArgumentAt(0); + $task = $this->createTask($name, $io); + if ($task) { + $argList = $args->getArguments(); + + // Remove command name. + array_shift($argList); + foreach ($args->getOptions() as $key => $value) { + if ($value === false) { + continue; + } elseif ($value === true) { + $argList[] = '--' . $key; + } else { + $argList[] = '--' . $key; + $argList[] = $value; + } + } + + $result = $task->runCommand($argList); + if ($result === false) { + return static::CODE_ERROR; + } + if ($result === true) { + return static::CODE_SUCCESS; + } + + return $result; + } + $io->err("Could not find a task named `{$name}`."); + + return static::CODE_ERROR; + } + $io->err('No command provided. Run `bake --help` to get a list of commands.'); + + return static::CODE_ERROR; + } + + /** + * Find and create a Shell based BakeTask + * + * @param string $name The task name. + * @param \Cake\Console\ConsoleIo $io The console io. + * @return \Cake\Console\Shell|null + */ + protected function createTask(string $name, ConsoleIo $io): ?Shell + { + $found = false; + $name = Inflector::camelize($name); + $factory = function ($className, $io) { + $task = new $className($io); + $task->setRootName('cake bake'); + + return $task; + }; + + // Look in each plugin for the requested task + foreach (CorePlugin::loaded() as $plugin) { + $namespace = str_replace('/', '\\', $plugin); + $candidate = $namespace . '\Shell\Task\\' . $name . 'Task'; + if (class_exists($candidate) && is_subclass_of($candidate, BakeTask::class)) { + return $factory($candidate, $io); + } + } + + // Try the app as well + $namespace = Configure::read('App.namespace'); + $candidate = $namespace . '\Shell\Task\\' . $name . 'Task'; + if (class_exists($candidate) && is_subclass_of($candidate, BakeTask::class)) { + return $factory($candidate, $io); + } + + return null; + } + + /** + * Gets the option parser instance and configures it. + * + * @param \Cake\Console\ConsoleOptionParser $parser The console option parser + * @return \Cake\Console\ConsoleOptionParser + */ + public function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser + { + $this->help = new HelpCommand(); + /** @psalm-suppress InaccessibleMethod Protected methods as class based */ + $parser = $this->help->buildOptionParser($parser); + $parser + ->setDescription( + 'Bake generates code for your application. Different types of classes can be generated' . + ' with the subcommands listed below. For example run bake controller --help' . + ' to learn more about generating a controller.' + ) + ->setEpilog('Older Shell based tasks will not be listed here, but can still be run.'); + $commands = []; + foreach ($this->commands as $command => $class) { + if (substr($command, 0, 4) === 'bake') { + $parts = explode(' ', $command); + + // Remove `bake` + array_shift($parts); + if (count($parts) === 0) { + continue; + } + $commands[$command] = $class; + } + } + + $CommandCollection = new CommandCollection($commands); + $this->help->setCommandCollection($CommandCollection); + + return $parser; + } +} diff --git a/app/vendor/cakephp/bake/src/Command/FixtureAllCommand.php b/app/vendor/cakephp/bake/src/Command/FixtureAllCommand.php new file mode 100644 index 000000000..e6268fc70 --- /dev/null +++ b/app/vendor/cakephp/bake/src/Command/FixtureAllCommand.php @@ -0,0 +1,96 @@ +_setCommonOptions($parser); + + $parser = $parser->setDescription( + 'Generate all fixtures for use with the test suite.' + )->addOption('count', [ + 'help' => 'When using generated data, the number of records to include in the fixture(s).', + 'short' => 'n', + 'default' => 1, + ])->addOption('schema', [ + 'help' => 'Create a fixture that imports schema, instead of dumping a schema snapshot into the fixture.', + 'short' => 's', + 'boolean' => true, + ])->addOption('records', [ + 'help' => 'Generate a fixture with records from the non-test database.' . + ' Used with --count and --conditions to limit which records are added to the fixture.', + 'short' => 'r', + 'boolean' => true, + ])->addOption('conditions', [ + 'help' => 'The SQL snippet to use when importing records.', + 'default' => '1=1', + ]); + + return $parser; + } + + /** + * Execute the command. + * + * @param \Cake\Console\Arguments $args The command arguments. + * @param \Cake\Console\ConsoleIo $io The console io + * @return int|null + */ + public function execute(Arguments $args, ConsoleIo $io): ?int + { + $this->extractCommonProperties($args); + + /** @var \Cake\Database\Connection $connection */ + $connection = ConnectionManager::get($args->getOption('connection') ?? 'default'); + $scanner = new TableScanner($connection); + $fixture = new FixtureCommand(); + foreach ($scanner->listUnskipped() as $table) { + $fixtureArgs = new Arguments([$table], $args->getOptions(), ['name']); + $fixture->execute($fixtureArgs, $io); + } + + return static::CODE_SUCCESS; + } +} diff --git a/app/vendor/cakephp/bake/src/Command/FixtureCommand.php b/app/vendor/cakephp/bake/src/Command/FixtureCommand.php new file mode 100644 index 000000000..1fd184934 --- /dev/null +++ b/app/vendor/cakephp/bake/src/Command/FixtureCommand.php @@ -0,0 +1,457 @@ +plugin) { + $path = $this->_pluginPath($this->plugin) . 'tests/' . $dir; + } + + return str_replace('/', DS, $path); + } + + /** + * Gets the option parser instance and configures it. + * + * @param \Cake\Console\ConsoleOptionParser $parser Option parser to update. + * @return \Cake\Console\ConsoleOptionParser + */ + public function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser + { + $parser = $this->_setCommonOptions($parser); + + $parser = $parser->setDescription( + 'Generate fixtures for use with the test suite. You can use `bake fixture all` to bake all fixtures.' + )->addArgument('name', [ + 'help' => 'Name of the fixture to bake (without the `Fixture` suffix). ' . + 'You can use Plugin.name to bake plugin fixtures.', + ])->addOption('table', [ + 'help' => 'The table name if it does not follow conventions.', + ])->addOption('count', [ + 'help' => 'When using generated data, the number of records to include in the fixture(s).', + 'short' => 'n', + 'default' => 1, + ])->addOption('schema', [ + 'help' => 'Create a fixture that imports schema, instead of dumping a schema snapshot into the fixture.', + 'short' => 's', + 'boolean' => true, + ])->addOption('records', [ + 'help' => 'Generate a fixture with records from the non-test database.' . + ' Used with --count and --conditions to limit which records are added to the fixture.', + 'short' => 'r', + 'boolean' => true, + ])->addOption('conditions', [ + 'help' => 'The SQL snippet to use when importing records.', + 'default' => '1=1', + ]); + + return $parser; + } + + /** + * Execute the command. + * + * @param \Cake\Console\Arguments $args The command arguments. + * @param \Cake\Console\ConsoleIo $io The console io + * @return int|null The exit code or null for success + */ + public function execute(Arguments $args, ConsoleIo $io): ?int + { + $this->extractCommonProperties($args); + $name = $args->getArgument('name') ?? ''; + $name = $this->_getName($name); + + /** @var \Cake\Database\Connection $connection */ + $connection = ConnectionManager::get($this->connection); + $scanner = new TableScanner($connection); + if (empty($name)) { + $io->out('Choose a fixture to bake from the following:'); + foreach ($scanner->listUnskipped() as $table) { + $io->out('- ' . $this->_camelize($table)); + } + + return static::CODE_SUCCESS; + } + + $table = $args->getOption('table') ?? ''; + $model = $this->_camelize($name); + $this->bake($model, $table, $args, $io); + + return static::CODE_SUCCESS; + } + + /** + * Assembles and writes a Fixture file + * + * @param string $model Name of model to bake. + * @param string $useTable Name of table to use. + * @param \Cake\Console\Arguments $args The command arguments. + * @param \Cake\Console\ConsoleIo $io The console io + * @return void + * @throws \RuntimeException + */ + protected function bake(string $model, string $useTable, Arguments $args, ConsoleIo $io): void + { + $table = $schema = $records = $import = $modelImport = null; + + if (!$useTable) { + $useTable = Inflector::tableize($model); + } elseif ($useTable !== Inflector::tableize($model)) { + $table = $useTable; + } + + $importBits = []; + if ($args->getOption('schema')) { + $modelImport = true; + $importBits[] = "'table' => '{$useTable}'"; + } + if (!empty($importBits) && $this->connection !== 'default') { + $importBits[] = "'connection' => '{$this->connection}'"; + } + if (!empty($importBits)) { + $import = sprintf('[%s]', implode(', ', $importBits)); + } + + try { + $data = $this->readSchema($model, $useTable); + } catch (Exception $e) { + $this->getTableLocator()->remove($model); + $useTable = Inflector::underscore($model); + $table = $useTable; + $data = $this->readSchema($model, $useTable); + } + + if ($modelImport === null) { + $schema = $this->_generateSchema($data); + } + + if ($args->getOption('records')) { + $records = $this->_makeRecordString($this->_getRecordsFromTable($args, $model, $useTable)); + } else { + $recordCount = 1; + if ($args->hasOption('count')) { + $recordCount = (int)$args->getOption('count'); + } + $records = $this->_makeRecordString($this->_generateRecords($data, $recordCount)); + } + + $this->generateFixtureFile($args, $io, $model, compact('records', 'table', 'schema', 'import')); + } + + /** + * Get schema metadata for the current table mapping. + * + * @param string $name The model alias to use + * @param string $table The table name to get schema metadata for. + * @return \Cake\Database\Schema\TableSchemaInterface + */ + public function readSchema(string $name, string $table): TableSchemaInterface + { + $connection = ConnectionManager::get($this->connection); + + if ($this->getTableLocator()->exists($name)) { + $model = $this->getTableLocator()->get($name); + } else { + $model = $this->getTableLocator()->get($name, [ + 'table' => $table, + 'connection' => $connection, + ]); + } + + return $model->getSchema(); + } + + /** + * Generate the fixture file, and write to disk + * + * @param \Cake\Console\Arguments $args The CLI arguments. + * @param \Cake\Console\ConsoleIo $io The console io instance. + * @param string $model name of the model being generated + * @param array $otherVars Contents of the fixture file. + * @return void + */ + public function generateFixtureFile(Arguments $args, ConsoleIo $io, string $model, array $otherVars): void + { + $defaults = [ + 'name' => $model, + 'table' => null, + 'schema' => null, + 'records' => null, + 'import' => null, + 'fields' => null, + 'namespace' => Configure::read('App.namespace'), + ]; + if ($this->plugin) { + $defaults['namespace'] = $this->_pluginNamespace($this->plugin); + } + $vars = $otherVars + $defaults; + + $path = $this->getPath($args); + $filename = $vars['name'] . 'Fixture.php'; + + $renderer = new TemplateRenderer($args->getOption('theme')); + $renderer->set('model', $model); + $renderer->set($vars); + $content = $renderer->generate('Bake.tests/fixture'); + + $io->out("\n" . sprintf('Baking test fixture for %s...', $model), 1, ConsoleIo::QUIET); + $io->createFile($path . $filename, $content, $args->getOption('force')); + $emptyFile = $path . '.gitkeep'; + $this->deleteEmptyFile($emptyFile, $io); + } + + /** + * Generates a string representation of a schema. + * + * @param \Cake\Database\Schema\TableSchemaInterface $table Table schema + * @return string fields definitions + */ + protected function _generateSchema(TableSchemaInterface $table): string + { + $cols = $indexes = $constraints = []; + foreach ($table->columns() as $field) { + $fieldData = $table->getColumn($field); + $properties = implode(', ', $this->_values($fieldData)); + $cols[] = " '$field' => [$properties],"; + } + foreach ($table->indexes() as $index) { + $fieldData = $table->getIndex($index); + $properties = implode(', ', $this->_values($fieldData)); + $indexes[] = " '$index' => [$properties],"; + } + foreach ($table->constraints() as $index) { + $fieldData = $table->getConstraint($index); + $properties = implode(', ', $this->_values($fieldData)); + $constraints[] = " '$index' => [$properties],"; + } + $options = $this->_values($table->getOptions()); + + $content = implode("\n", $cols) . "\n"; + if (!empty($indexes)) { + $content .= " '_indexes' => [\n" . implode("\n", $indexes) . "\n ],\n"; + } + if (!empty($constraints)) { + $content .= " '_constraints' => [\n" . implode("\n", $constraints) . "\n ],\n"; + } + if (!empty($options)) { + foreach ($options as &$option) { + $option = ' ' . $option; + } + $content .= " '_options' => [\n" . implode(",\n", $options) . "\n ],\n"; + } + + return "[\n$content ]"; + } + + /** + * Formats Schema columns from Model Object + * + * @param array $values options keys(type, null, default, key, length, extra) + * @return string[] Formatted values + */ + protected function _values(array $values): array + { + $vals = []; + + foreach ($values as $key => $val) { + if (is_array($val)) { + $vals[] = "'{$key}' => [" . implode(', ', $this->_values($val)) . ']'; + } else { + $val = var_export($val, true); + if ($val === 'NULL') { + $val = 'null'; + } + if (!is_numeric($key)) { + $vals[] = "'{$key}' => {$val}"; + } else { + $vals[] = "{$val}"; + } + } + } + + return $vals; + } + + /** + * Generate String representation of Records + * + * @param \Cake\Database\Schema\TableSchemaInterface $table Table schema array + * @param int $recordCount The number of records to generate. + * @return array Array of records to use in the fixture. + */ + protected function _generateRecords(TableSchemaInterface $table, int $recordCount = 1): array + { + $records = []; + for ($i = 0; $i < $recordCount; $i++) { + $record = []; + foreach ($table->columns() as $field) { + $fieldInfo = $table->getColumn($field); + $insert = ''; + switch ($fieldInfo['type']) { + case 'decimal': + $insert = $i + 1.5; + break; + case 'biginteger': + case 'integer': + case 'float': + case 'smallinteger': + case 'tinyinteger': + $insert = $i + 1; + break; + case 'string': + case 'binary': + $isPrimary = in_array($field, $table->getPrimaryKey()); + if ($isPrimary) { + $insert = Text::uuid(); + } else { + $insert = 'Lorem ipsum dolor sit amet'; + if (!empty($fieldInfo['length'])) { + $insert = substr( + $insert, + 0, + (int)$fieldInfo['length'] > 2 + ? (int)$fieldInfo['length'] - 2 + : (int)$fieldInfo['length'] + ); + } + } + break; + case 'timestamp': + case 'timestamptimezone': + case 'timestampfractional': + $insert = time(); + break; + case 'datetime': + $insert = date('Y-m-d H:i:s'); + break; + case 'date': + $insert = date('Y-m-d'); + break; + case 'time': + $insert = date('H:i:s'); + break; + case 'boolean': + $insert = 1; + break; + case 'text': + $insert = 'Lorem ipsum dolor sit amet, aliquet feugiat.'; + $insert .= ' Convallis morbi fringilla gravida,'; + $insert .= ' phasellus feugiat dapibus velit nunc, pulvinar eget sollicitudin'; + $insert .= ' venenatis cum nullam, vivamus ut a sed, mollitia lectus. Nulla'; + $insert .= ' vestibulum massa neque ut et, id hendrerit sit,'; + $insert .= ' feugiat in taciti enim proin nibh, tempor dignissim, rhoncus'; + $insert .= ' duis vestibulum nunc mattis convallis.'; + break; + case 'uuid': + $insert = Text::uuid(); + break; + } + $record[$field] = $insert; + } + $records[] = $record; + } + + return $records; + } + + /** + * Convert a $records array into a string. + * + * @param array $records Array of records to be converted to string + * @return string A string value of the $records array. + */ + protected function _makeRecordString(array $records): string + { + $out = "[\n"; + foreach ($records as $record) { + $values = []; + foreach ($record as $field => $value) { + if ($value instanceof DateTimeInterface) { + $value = $value->format('Y-m-d H:i:s'); + } + $val = var_export($value, true); + if ($val === 'NULL') { + $val = 'null'; + } + $values[] = " '$field' => $val"; + } + $out .= " [\n"; + $out .= implode(",\n", $values); + $out .= ",\n ],\n"; + } + $out .= ' ]'; + + return $out; + } + + /** + * Interact with the user to get a custom SQL condition and use that to extract data + * to build a fixture. + * + * @param \Cake\Console\Arguments $args CLI arguments + * @param string $modelName name of the model to take records from. + * @param string|null $useTable Name of table to use. + * @return array Array of records. + */ + protected function _getRecordsFromTable(Arguments $args, string $modelName, ?string $useTable = null): array + { + $recordCount = ($args->getOption('count') ?? 10); + /** @var string $conditions */ + $conditions = ($args->getOption('conditions') ?? '1=1'); + if ($this->getTableLocator()->exists($modelName)) { + $model = $this->getTableLocator()->get($modelName); + } else { + $model = $this->getTableLocator()->get($modelName, [ + 'table' => $useTable, + 'connection' => ConnectionManager::get($this->connection), + ]); + } + $records = $model->find('all') + ->where($conditions) + ->limit((int)$recordCount) + ->enableHydration(false); + + return $records->toArray(); + } +} diff --git a/app/vendor/cakephp/bake/src/Command/FormCommand.php b/app/vendor/cakephp/bake/src/Command/FormCommand.php new file mode 100644 index 000000000..f84572bad --- /dev/null +++ b/app/vendor/cakephp/bake/src/Command/FormCommand.php @@ -0,0 +1,54 @@ +modelCommand = new ModelCommand(); + } + + /** + * Gets the option parser instance and configures it. + * + * @param \Cake\Console\ConsoleOptionParser $parser The parser to configure + * @return \Cake\Console\ConsoleOptionParser + */ + public function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser + { + $parser = $this->modelCommand->buildOptionParser($parser); + $parser + ->setDescription('Bake all model files with associations and validation.') + ->setEpilog(''); + + return $parser; + } + + /** + * Execute the command. + * + * @param \Cake\Console\Arguments $args The command arguments. + * @param \Cake\Console\ConsoleIo $io The console io + * @return int|null The exit code or null for success + */ + public function execute(Arguments $args, ConsoleIo $io): ?int + { + $this->extractCommonProperties($args); + /** @var \Cake\Database\Connection $connection */ + $connection = ConnectionManager::get($this->connection); + $scanner = new TableScanner($connection); + foreach ($scanner->listUnskipped() as $table) { + $this->getTableLocator()->clear(); + $modelArgs = new Arguments([$table], $args->getOptions(), ['name']); + $this->modelCommand->execute($modelArgs, $io); + } + + return static::CODE_SUCCESS; + } +} diff --git a/app/vendor/cakephp/bake/src/Command/ModelCommand.php b/app/vendor/cakephp/bake/src/Command/ModelCommand.php new file mode 100644 index 000000000..2be46282b --- /dev/null +++ b/app/vendor/cakephp/bake/src/Command/ModelCommand.php @@ -0,0 +1,1205 @@ +extractCommonProperties($args); + $name = $this->_getName($args->getArgument('name') ?? ''); + + if (empty($name)) { + $io->out('Choose a model to bake from the following:'); + foreach ($this->listUnskipped() as $table) { + $io->out('- ' . $this->_camelize($table)); + } + + return static::CODE_SUCCESS; + } + + $this->bake($this->_camelize($name), $args, $io); + + return static::CODE_SUCCESS; + } + + /** + * Generate code for the given model name. + * + * @param string $name The model name to generate. + * @param \Cake\Console\Arguments $args Console Arguments. + * @param \Cake\Console\ConsoleIo $io Console Io. + * @return void + */ + public function bake(string $name, Arguments $args, ConsoleIo $io): void + { + $table = $this->getTable($name, $args); + $tableObject = $this->getTableObject($name, $table); + $data = $this->getTableContext($tableObject, $table, $name, $args, $io); + $this->bakeTable($tableObject, $data, $args, $io); + $this->bakeEntity($tableObject, $data, $args, $io); + $this->bakeFixture($tableObject->getAlias(), $tableObject->getTable(), $args, $io); + $this->bakeTest($tableObject->getAlias(), $args, $io); + } + + /** + * Get table context for baking a given table. + * + * @param \Cake\ORM\Table $tableObject The model name to generate. + * @param string $table The table name for the model being baked. + * @param string $name The model name to generate. + * @param \Cake\Console\Arguments $args CLI Arguments + * @param \Cake\Console\ConsoleIo $io CLI io + * @return array + */ + public function getTableContext( + Table $tableObject, + string $table, + string $name, + Arguments $args, + ConsoleIo $io + ): array { + $associations = $this->getAssociations($tableObject, $args, $io); + $this->applyAssociations($tableObject, $associations); + $associationInfo = $this->getAssociationInfo($tableObject); + + $primaryKey = $this->getPrimaryKey($tableObject, $args); + $displayField = $this->getDisplayField($tableObject, $args); + $propertySchema = $this->getEntityPropertySchema($tableObject); + $fields = $this->getFields($tableObject, $args); + $validation = $this->getValidation($tableObject, $associations, $args); + $rulesChecker = $this->getRules($tableObject, $associations, $args); + $behaviors = $this->getBehaviors($tableObject); + $connection = $this->connection; + $hidden = $this->getHiddenFields($tableObject, $args); + + return compact( + 'associations', + 'associationInfo', + 'primaryKey', + 'displayField', + 'table', + 'propertySchema', + 'fields', + 'validation', + 'rulesChecker', + 'behaviors', + 'connection', + 'hidden' + ); + } + + /** + * Get a model object for a class name. + * + * @param string $className Name of class you want model to be. + * @param string $table Table name + * @return \Cake\ORM\Table Table instance + */ + public function getTableObject(string $className, string $table): Table + { + if (!empty($this->plugin)) { + $className = $this->plugin . '.' . $className; + } + + if ($this->getTableLocator()->exists($className)) { + return $this->getTableLocator()->get($className); + } + + return $this->getTableLocator()->get($className, [ + 'name' => $className, + 'table' => $this->tablePrefix . $table, + 'connection' => ConnectionManager::get($this->connection), + ]); + } + + /** + * Get the array of associations to generate. + * + * @param \Cake\ORM\Table $table The table to get associations for. + * @param \Cake\Console\Arguments $args CLI Arguments + * @param \Cake\Console\ConsoleIo $io CLI io + * @return array + */ + public function getAssociations(Table $table, Arguments $args, ConsoleIo $io): array + { + if ($args->getOption('no-associations')) { + return []; + } + $io->out('One moment while associations are detected.'); + + $this->listAll(); + + $associations = [ + 'belongsTo' => [], + 'hasMany' => [], + 'belongsToMany' => [], + ]; + + $primary = $table->getPrimaryKey(); + $associations = $this->findBelongsTo($table, $associations); + + if (is_array($primary) && count($primary) > 1) { + $io->warning( + 'Bake cannot generate associations for composite primary keys at this time.' + ); + + return $associations; + } + + $associations = $this->findHasMany($table, $associations); + $associations = $this->findBelongsToMany($table, $associations); + + return $associations; + } + + /** + * Sync the in memory table object. + * + * Composer's class cache prevents us from loading the + * newly generated class. Applying associations if we have a + * generic table object means fields will be detected correctly. + * + * @param \Cake\ORM\Table $model The table to apply associations to. + * @param array $associations The associations to append. + * @return void + */ + public function applyAssociations(Table $model, array $associations): void + { + if (get_class($model) !== Table::class) { + return; + } + foreach ($associations as $type => $assocs) { + foreach ($assocs as $assoc) { + $alias = $assoc['alias']; + unset($assoc['alias']); + $model->{$type}($alias, $assoc); + } + } + } + + /** + * Collects meta information for associations. + * + * The information returned is in the format of map, where the key is the + * association alias: + * + * ``` + * [ + * 'associationAlias' => [ + * 'targetFqn' => '...' + * ], + * // ... + * ] + * ``` + * + * @param \Cake\ORM\Table $table The table from which to collect association information. + * @return array A map of association information. + */ + public function getAssociationInfo(Table $table): array + { + $info = []; + + $appNamespace = Configure::read('App.namespace'); + + foreach ($table->associations() as $association) { + /** @var \Cake\ORM\Association $association */ + + $tableClass = get_class($association->getTarget()); + if ($tableClass === Table::class) { + $namespace = $appNamespace; + + $className = $association->getClassName(); + [$plugin, $className] = pluginSplit($className); + if ($plugin !== null) { + $namespace = $plugin; + } + + $namespace = str_replace('/', '\\', trim($namespace, '\\')); + $tableClass = $namespace . '\Model\Table\\' . $className . 'Table'; + } + + $info[$association->getName()] = [ + 'targetFqn' => '\\' . $tableClass, + ]; + } + + return $info; + } + + /** + * Find belongsTo relations and add them to the associations list. + * + * @param \Cake\ORM\Table $model Database\Table instance of table being generated. + * @param array $associations Array of in progress associations + * @return array Associations with belongsTo added in. + */ + public function findBelongsTo(Table $model, array $associations): array + { + $schema = $model->getSchema(); + foreach ($schema->columns() as $fieldName) { + if (!preg_match('/^.+_id$/', $fieldName) || ($schema->getPrimaryKey() === [$fieldName])) { + continue; + } + + if ($fieldName === 'parent_id') { + $className = $this->plugin ? $this->plugin . '.' . $model->getAlias() : $model->getAlias(); + $assoc = [ + 'alias' => 'Parent' . $model->getAlias(), + 'className' => $className, + 'foreignKey' => $fieldName, + ]; + } else { + $tmpModelName = $this->_modelNameFromKey($fieldName); + if (!in_array(Inflector::tableize($tmpModelName), $this->_tables, true)) { + $found = $this->findTableReferencedBy($schema, $fieldName); + if ($found) { + $tmpModelName = Inflector::camelize($found); + } + } + $assoc = [ + 'alias' => $tmpModelName, + 'foreignKey' => $fieldName, + ]; + if ($schema->getColumn($fieldName)['null'] === false) { + $assoc['joinType'] = 'INNER'; + } + } + + if ($this->plugin && empty($assoc['className'])) { + $assoc['className'] = $this->plugin . '.' . $assoc['alias']; + } + $associations['belongsTo'][] = $assoc; + } + + return $associations; + } + + /** + * find the table, if any, actually referenced by the passed key field. + * Search tables in db for keyField; if found search key constraints + * for the table to which it refers. + * + * @param \Cake\Database\Schema\TableSchemaInterface $schema The table schema to find a constraint for. + * @param string $keyField The field to check for a constraint. + * @return string|null Either the referenced table or null if the field has no constraints. + */ + public function findTableReferencedBy(TableSchemaInterface $schema, string $keyField): ?string + { + if (!$schema->getColumn($keyField)) { + return null; + } + + foreach ($schema->constraints() as $constraint) { + $constraintInfo = $schema->getConstraint($constraint); + if (!in_array($keyField, $constraintInfo['columns'])) { + continue; + } + + if (!isset($constraintInfo['references'])) { + continue; + } + $length = $this->tablePrefix ? mb_strlen($this->tablePrefix) : 0; + if ($length > 0 && mb_substr($constraintInfo['references'][0], 0, $length) === $this->tablePrefix) { + return mb_substr($constraintInfo['references'][0], $length); + } + + return $constraintInfo['references'][0]; + } + + return null; + } + + /** + * Find the hasMany relations and add them to associations list + * + * @param \Cake\ORM\Table $model Model instance being generated + * @param array $associations Array of in progress associations + * @return array Associations with hasMany added in. + */ + public function findHasMany(Table $model, array $associations): array + { + $schema = $model->getSchema(); + $primaryKey = $schema->getPrimaryKey(); + $tableName = $schema->name(); + $foreignKey = $this->_modelKey($tableName); + + $tables = $this->listAll(); + foreach ($tables as $otherTableName) { + $otherModel = $this->getTableObject($this->_camelize($otherTableName), $otherTableName); + $otherSchema = $otherModel->getSchema(); + + $pregTableName = preg_quote($tableName, '/'); + $pregPattern = "/^{$pregTableName}_|_{$pregTableName}$/"; + if (preg_match($pregPattern, $otherTableName) === 1) { + $possibleHABTMTargetTable = preg_replace($pregPattern, '', $otherTableName); + if (in_array($possibleHABTMTargetTable, $tables)) { + continue; + } + } + + foreach ($otherSchema->columns() as $fieldName) { + $assoc = false; + if (!in_array($fieldName, $primaryKey) && $fieldName === $foreignKey) { + $assoc = [ + 'alias' => $otherModel->getAlias(), + 'foreignKey' => $fieldName, + ]; + } elseif ($otherTableName === $tableName && $fieldName === 'parent_id') { + $className = $this->plugin ? $this->plugin . '.' . $model->getAlias() : $model->getAlias(); + $assoc = [ + 'alias' => 'Child' . $model->getAlias(), + 'className' => $className, + 'foreignKey' => $fieldName, + ]; + } + if ($assoc && $this->plugin && empty($assoc['className'])) { + $assoc['className'] = $this->plugin . '.' . $assoc['alias']; + } + if ($assoc) { + $associations['hasMany'][] = $assoc; + } + } + } + + return $associations; + } + + /** + * Find the BelongsToMany relations and add them to associations list + * + * @param \Cake\ORM\Table $model Model instance being generated + * @param array $associations Array of in-progress associations + * @return array Associations with belongsToMany added in. + */ + public function findBelongsToMany(Table $model, array $associations): array + { + $schema = $model->getSchema(); + $tableName = $schema->name(); + $foreignKey = $this->_modelKey($tableName); + + $tables = $this->listAll(); + foreach ($tables as $otherTableName) { + $assocTable = null; + $offset = strpos($otherTableName, $tableName . '_'); + $otherOffset = strpos($otherTableName, '_' . $tableName); + + if ($offset !== false) { + $assocTable = substr($otherTableName, strlen($tableName . '_')); + } elseif ($otherOffset !== false) { + $assocTable = substr($otherTableName, 0, $otherOffset); + } + if ($assocTable && in_array($assocTable, $tables)) { + $habtmName = $this->_camelize($assocTable); + $assoc = [ + 'alias' => $habtmName, + 'foreignKey' => $foreignKey, + 'targetForeignKey' => $this->_modelKey($habtmName), + 'joinTable' => $otherTableName, + ]; + if ($this->plugin) { + $assoc['className'] = $this->plugin . '.' . $assoc['alias']; + } + $associations['belongsToMany'][] = $assoc; + } + } + + return $associations; + } + + /** + * Get the display field from the model or parameters + * + * @param \Cake\ORM\Table $model The model to introspect. + * @param \Cake\Console\Arguments $args CLI Arguments + * @return string|null + * @psalm-suppress InvalidReturnType + */ + public function getDisplayField(Table $model, Arguments $args): ?string + { + if ($args->getOption('display-field')) { + return (string)$args->getOption('display-field'); + } + + /** @psalm-suppress InvalidReturnStatement */ + return $model->getDisplayField(); + } + + /** + * Get the primary key field from the model or parameters + * + * @param \Cake\ORM\Table $model The model to introspect. + * @param \Cake\Console\Arguments $args CLI Arguments + * @return string[] The columns in the primary key + */ + public function getPrimaryKey(Table $model, Arguments $args): array + { + if ($args->getOption('primary-key')) { + $fields = explode(',', $args->getOption('primary-key')); + + return array_values(array_filter(array_map('trim', $fields))); + } + + return (array)$model->getPrimaryKey(); + } + + /** + * Returns an entity property "schema". + * + * The schema is an associative array, using the property names + * as keys, and information about the property as the value. + * + * The value part consists of at least two keys: + * + * - `kind`: The kind of property, either `column`, which indicates + * that the property stems from a database column, or `association`, + * which identifies a property that is generated for an associated + * table. + * - `type`: The type of the property value. For the `column` kind + * this is the database type associated with the column, and for the + * `association` type it's the FQN of the entity class for the + * associated table. + * + * For `association` properties an additional key will be available + * + * - `association`: Holds an instance of the corresponding association + * class. + * + * @param \Cake\ORM\Table $model The model to introspect. + * @return array The property schema + */ + public function getEntityPropertySchema(Table $model): array + { + $properties = []; + + $schema = $model->getSchema(); + foreach ($schema->columns() as $column) { + $columnSchema = $schema->getColumn($column); + + $properties[$column] = [ + 'kind' => 'column', + 'type' => $columnSchema['type'], + 'null' => $columnSchema['null'], + ]; + } + + foreach ($model->associations() as $association) { + $entityClass = '\\' . ltrim($association->getTarget()->getEntityClass(), '\\'); + + if ($entityClass === '\Cake\ORM\Entity') { + $namespace = Configure::read('App.namespace'); + + [$plugin, ] = pluginSplit($association->getTarget()->getRegistryAlias()); + if ($plugin !== null) { + $namespace = $plugin; + } + $namespace = str_replace('/', '\\', trim($namespace, '\\')); + + $entityClass = $this->_entityName($association->getTarget()->getAlias()); + $entityClass = '\\' . $namespace . '\Model\Entity\\' . $entityClass; + } + + $properties[$association->getProperty()] = [ + 'kind' => 'association', + 'association' => $association, + 'type' => $entityClass, + ]; + } + + return $properties; + } + + /** + * Evaluates the fields and no-fields options, and + * returns if, and which fields should be made accessible. + * + * If no fields are specified and the `no-fields` parameter is + * not set, then all non-primary key fields + association + * fields will be set as accessible. + * + * @param \Cake\ORM\Table $table The table instance to get fields for. + * @param \Cake\Console\Arguments $args CLI Arguments + * @return string[]|false|null Either an array of fields, `false` in + * case the no-fields option is used, or `null` if none of the + * field options is used. + */ + public function getFields(Table $table, Arguments $args) + { + if ($args->getOption('no-fields')) { + return false; + } + if ($args->getOption('fields')) { + $fields = explode(',', $args->getOption('fields')); + + return array_values(array_filter(array_map('trim', $fields))); + } + $schema = $table->getSchema(); + $fields = $schema->columns(); + foreach ($table->associations() as $assoc) { + $fields[] = $assoc->getProperty(); + } + $primaryKey = $schema->getPrimaryKey(); + + return array_values(array_diff($fields, $primaryKey)); + } + + /** + * Get the hidden fields from a model. + * + * Uses the hidden and no-hidden options. + * + * @param \Cake\ORM\Table $model The model to introspect. + * @param \Cake\Console\Arguments $args CLI Arguments + * @return string[] The columns to make accessible + */ + public function getHiddenFields(Table $model, Arguments $args): array + { + if ($args->getOption('no-hidden')) { + return []; + } + if ($args->getOption('hidden')) { + $fields = explode(',', $args->getOption('hidden')); + + return array_values(array_filter(array_map('trim', $fields))); + } + $schema = $model->getSchema(); + $columns = $schema->columns(); + $whitelist = ['token', 'password', 'passwd']; + + return array_values(array_intersect($columns, $whitelist)); + } + + /** + * Generate default validation rules. + * + * @param \Cake\ORM\Table $model The model to introspect. + * @param array $associations The associations list. + * @param \Cake\Console\Arguments $args CLI Arguments + * @return array|false The validation rules. + */ + public function getValidation(Table $model, array $associations, Arguments $args) + { + if ($args->getOption('no-validation')) { + return []; + } + $schema = $model->getSchema(); + $fields = $schema->columns(); + if (!$fields) { + return false; + } + + $validate = []; + $primaryKey = $schema->getPrimaryKey(); + $foreignKeys = []; + if (isset($associations['belongsTo'])) { + foreach ($associations['belongsTo'] as $assoc) { + $foreignKeys[] = $assoc['foreignKey']; + } + } + foreach ($fields as $fieldName) { + if (in_array($fieldName, $foreignKeys, true)) { + continue; + } + $field = $schema->getColumn($fieldName); + $validation = $this->fieldValidation($schema, $fieldName, $field, $primaryKey); + if ($validation) { + $validate[$fieldName] = $validation; + } + } + + return $validate; + } + + /** + * Does individual field validation handling. + * + * @param \Cake\Database\Schema\TableSchemaInterface $schema The table schema for the current field. + * @param string $fieldName Name of field to be validated. + * @param array $metaData metadata for field + * @param array $primaryKey The primary key field + * @return array Array of validation for the field. + */ + public function fieldValidation( + TableSchemaInterface $schema, + string $fieldName, + array $metaData, + array $primaryKey + ): array { + $ignoreFields = ['lft', 'rght', 'created', 'modified', 'updated']; + if (in_array($fieldName, $ignoreFields, true)) { + return []; + } + + $rules = []; + if ($fieldName === 'email') { + $rules['email'] = []; + } elseif ($metaData['type'] === 'uuid') { + $rules['uuid'] = []; + } elseif ($metaData['type'] === 'integer') { + if ($metaData['unsigned']) { + $rules['nonNegativeInteger'] = []; + } else { + $rules['integer'] = []; + } + } elseif ($metaData['type'] === 'float') { + $rules['numeric'] = []; + if ($metaData['unsigned']) { + $rules['greaterThanOrEqual'] = [ + 0, + ]; + } + } elseif ($metaData['type'] === 'decimal') { + $rules['decimal'] = []; + if ($metaData['unsigned']) { + $rules['greaterThanOrEqual'] = [ + 0, + ]; + } + } elseif ($metaData['type'] === 'boolean') { + $rules['boolean'] = []; + } elseif ($metaData['type'] === 'date') { + $rules['date'] = []; + } elseif ($metaData['type'] === 'time') { + $rules['time'] = []; + } elseif (strpos($metaData['type'], 'datetime') === 0) { + $rules['dateTime'] = []; + } elseif (strpos($metaData['type'], 'timestamp') === 0) { + $rules['dateTime'] = []; + } elseif ($metaData['type'] === 'inet') { + $rules['ip'] = []; + } elseif (in_array($metaData['type'], ['char', 'string', 'text'], true)) { + $rules['scalar'] = []; + if ($metaData['length'] > 0) { + $rules['maxLength'] = [$metaData['length']]; + } + } + + $validation = []; + foreach ($rules as $rule => $args) { + $validation[$rule] = [ + 'rule' => $rule, + 'args' => $args, + ]; + } + + if (in_array($fieldName, $primaryKey, true)) { + $validation['allowEmpty'] = [ + 'rule' => $this->getEmptyMethod($fieldName, $metaData), + 'args' => [null, 'create'], + ]; + } elseif ($metaData['null'] === true) { + $validation['allowEmpty'] = [ + 'rule' => $this->getEmptyMethod($fieldName, $metaData), + 'args' => [], + ]; + } else { + if ($metaData['default'] === null || $metaData['default'] === false) { + $validation['requirePresence'] = [ + 'rule' => 'requirePresence', + 'args' => ['create'], + ]; + } + $validation['notEmpty'] = [ + 'rule' => $this->getEmptyMethod($fieldName, $metaData, 'not'), + 'args' => [], + ]; + } + + foreach ($schema->constraints() as $constraint) { + $constraint = $schema->getConstraint($constraint); + if (!in_array($fieldName, $constraint['columns'], true) || count($constraint['columns']) > 1) { + continue; + } + + $timeTypes = [ + 'datetime', + 'timestamp', + 'datetimefractional', + 'timestampfractional', + 'timestamptimezone', + 'date', + 'time', + ]; + $notDatetime = !in_array($metaData['type'], $timeTypes, true); + if ($constraint['type'] === TableSchema::CONSTRAINT_UNIQUE && $notDatetime) { + $validation['unique'] = ['rule' => 'validateUnique', 'provider' => 'table']; + } + } + + return $validation; + } + + /** + * Get the specific allow empty method for field based on metadata. + * + * @param string $fieldName Field name. + * @param array $metaData Field meta data. + * @param string $prefix Method name prefix. + * @return string + */ + protected function getEmptyMethod(string $fieldName, array $metaData, string $prefix = 'allow'): string + { + switch ($metaData['type']) { + case 'date': + return $prefix . 'EmptyDate'; + + case 'time': + return $prefix . 'EmptyTime'; + + case 'datetime': + case 'datetimefractional': + case 'timestamp': + case 'timestampfractional': + case 'timestamptimezone': + return $prefix . 'EmptyDateTime'; + } + + if (preg_match('/file|image/', $fieldName)) { + return $prefix . 'EmptyFile'; + } + + return $prefix . 'EmptyString'; + } + + /** + * Generate default rules checker. + * + * @param \Cake\ORM\Table $model The model to introspect. + * @param array $associations The associations for the model. + * @param \Cake\Console\Arguments $args CLI Arguments + * @return array The rules to be applied. + */ + public function getRules(Table $model, array $associations, Arguments $args): array + { + if ($args->getOption('no-rules')) { + return []; + } + $schema = $model->getSchema(); + $fields = $schema->columns(); + if (empty($fields)) { + return []; + } + + $uniqueColumns = ['username', 'login']; + if (in_array($model->getAlias(), ['Users', 'Accounts'])) { + $uniqueColumns[] = 'email'; + } + + $rules = []; + foreach ($fields as $fieldName) { + if (in_array($fieldName, $uniqueColumns, true)) { + $rules[$fieldName] = ['name' => 'isUnique']; + } + } + foreach ($schema->constraints() as $name) { + $constraint = $schema->getConstraint($name); + if ($constraint['type'] !== TableSchema::CONSTRAINT_UNIQUE) { + continue; + } + if (count($constraint['columns']) > 1) { + continue; + } + $rules[$constraint['columns'][0]] = ['name' => 'isUnique']; + } + + if (empty($associations['belongsTo'])) { + return $rules; + } + + foreach ($associations['belongsTo'] as $assoc) { + $rules[$assoc['foreignKey']] = ['name' => 'existsIn', 'extra' => $assoc['alias']]; + } + + return $rules; + } + + /** + * Get behaviors + * + * @param \Cake\ORM\Table $model The model to generate behaviors for. + * @return array Behaviors + */ + public function getBehaviors(Table $model): array + { + $behaviors = []; + $schema = $model->getSchema(); + $fields = $schema->columns(); + if (empty($fields)) { + return []; + } + if (in_array('created', $fields, true) || in_array('modified', $fields, true)) { + $behaviors['Timestamp'] = []; + } + + if ( + in_array('lft', $fields, true) + && $schema->getColumnType('lft') === 'integer' + && in_array('rght', $fields, true) + && $schema->getColumnType('rght') === 'integer' + && in_array('parent_id', $fields, true) + ) { + $behaviors['Tree'] = []; + } + + $counterCache = $this->getCounterCache($model); + if (!empty($counterCache)) { + $behaviors['CounterCache'] = $counterCache; + } + + return $behaviors; + } + + /** + * Get CounterCaches + * + * @param \Cake\ORM\Table $model The table to get counter cache fields for. + * @return array CounterCache configurations + */ + public function getCounterCache(Table $model): array + { + $belongsTo = $this->findBelongsTo($model, ['belongsTo' => []]); + $counterCache = []; + foreach ($belongsTo['belongsTo'] as $otherTable) { + $otherAlias = $otherTable['alias']; + $otherModel = $this->getTableObject($this->_camelize($otherAlias), Inflector::underscore($otherAlias)); + + try { + $otherSchema = $otherModel->getSchema(); + } catch (Exception $e) { + continue; + } + + $otherFields = $otherSchema->columns(); + $alias = $model->getAlias(); + $field = Inflector::singularize(Inflector::underscore($alias)) . '_count'; + if (in_array($field, $otherFields, true)) { + $counterCache[$otherAlias] = [$field]; + } + } + + return $counterCache; + } + + /** + * Bake an entity class. + * + * @param \Cake\ORM\Table $model Model name or object + * @param array $data An array to use to generate the Table + * @param \Cake\Console\Arguments $args CLI Arguments + * @param \Cake\Console\ConsoleIo $io CLI io + * @return void + */ + public function bakeEntity(Table $model, array $data, Arguments $args, ConsoleIo $io): void + { + if ($args->getOption('no-entity')) { + return; + } + $name = $this->_entityName($model->getAlias()); + + $namespace = Configure::read('App.namespace'); + $pluginPath = ''; + if ($this->plugin) { + $namespace = $this->_pluginNamespace($this->plugin); + $pluginPath = $this->plugin . '.'; + } + + $data += [ + 'name' => $name, + 'namespace' => $namespace, + 'plugin' => $this->plugin, + 'pluginPath' => $pluginPath, + 'primaryKey' => [], + ]; + + $renderer = new TemplateRenderer($this->theme); + $renderer->set($data); + $out = $renderer->generate('Bake.Model/entity'); + + $path = $this->getPath($args); + $filename = $path . 'Entity' . DS . $name . '.php'; + $io->out("\n" . sprintf('Baking entity class for %s...', $name), 1, ConsoleIo::QUIET); + $io->createFile($filename, $out, $args->getOption('force')); + + $emptyFile = $path . 'Entity' . DS . '.gitkeep'; + $this->deleteEmptyFile($emptyFile, $io); + } + + /** + * Bake a table class. + * + * @param \Cake\ORM\Table $model Model name or object + * @param array $data An array to use to generate the Table + * @param \Cake\Console\Arguments $args CLI Arguments + * @param \Cake\Console\ConsoleIo $io CLI Arguments + * @return void + */ + public function bakeTable(Table $model, array $data, Arguments $args, ConsoleIo $io): void + { + if ($args->getOption('no-table')) { + return; + } + + $namespace = Configure::read('App.namespace'); + $pluginPath = ''; + if ($this->plugin) { + $namespace = $this->_pluginNamespace($this->plugin); + } + + $name = $model->getAlias(); + $entity = $this->_entityName($model->getAlias()); + $data += [ + 'plugin' => $this->plugin, + 'pluginPath' => $pluginPath, + 'namespace' => $namespace, + 'name' => $name, + 'entity' => $entity, + 'associations' => [], + 'primaryKey' => 'id', + 'displayField' => null, + 'table' => null, + 'validation' => [], + 'rulesChecker' => [], + 'behaviors' => [], + 'connection' => $this->connection, + ]; + + $renderer = new TemplateRenderer($this->theme); + $renderer->set($data); + $out = $renderer->generate('Bake.Model/table'); + + $path = $this->getPath($args); + $filename = $path . 'Table' . DS . $name . 'Table.php'; + $io->out("\n" . sprintf('Baking table class for %s...', $name), 1, ConsoleIo::QUIET); + $io->createFile($filename, $out, $args->getOption('force')); + + // Work around composer caching that classes/files do not exist. + // Check for the file as it might not exist in tests. + if (file_exists($filename)) { + require_once $filename; + } + $this->getTableLocator()->clear(); + + $emptyFile = $path . 'Table' . DS . '.gitkeep'; + $this->deleteEmptyFile($emptyFile, $io); + } + + /** + * Outputs the a list of possible models or controllers from database + * + * @return string[] + */ + public function listAll(): array + { + if (!empty($this->_tables)) { + return $this->_tables; + } + + /** @var \Cake\Database\Connection $connection */ + $connection = ConnectionManager::get($this->connection); + $scanner = new TableScanner($connection); + $this->_tables = $scanner->listAll(); + + return $this->_tables; + } + + /** + * Outputs the a list of unskipped models or controllers from database + * + * @return string[] + */ + public function listUnskipped(): array + { + /** @var \Cake\Database\Connection $connection */ + $connection = ConnectionManager::get($this->connection); + $scanner = new TableScanner($connection); + + return $scanner->listUnskipped(); + } + + /** + * Get the table name for the model being baked. + * + * Uses the `table` option if it is set. + * + * @param string $name Table name + * @param \Cake\Console\Arguments $args The CLI arguments + * @return string + */ + public function getTable(string $name, Arguments $args): string + { + if ($args->getOption('table')) { + return (string)$args->getOption('table'); + } + + return Inflector::underscore($name); + } + + /** + * Gets the option parser instance and configures it. + * + * @param \Cake\Console\ConsoleOptionParser $parser The parser to configure + * @return \Cake\Console\ConsoleOptionParser + */ + public function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser + { + $parser = $this->_setCommonOptions($parser); + + $parser->setDescription( + 'Bake table and entity classes.' + )->addArgument('name', [ + 'help' => 'Name of the model to bake (without the Table suffix). ' . + 'You can use Plugin.name to bake plugin models.', + ])->addOption('table', [ + 'help' => 'The table name to use if you have non-conventional table names.', + ])->addOption('no-entity', [ + 'boolean' => true, + 'help' => 'Disable generating an entity class.', + ])->addOption('no-table', [ + 'boolean' => true, + 'help' => 'Disable generating a table class.', + ])->addOption('no-validation', [ + 'boolean' => true, + 'help' => 'Disable generating validation rules.', + ])->addOption('no-rules', [ + 'boolean' => true, + 'help' => 'Disable generating a rules checker.', + ])->addOption('no-associations', [ + 'boolean' => true, + 'help' => 'Disable generating associations.', + ])->addOption('no-fields', [ + 'boolean' => true, + 'help' => 'Disable generating accessible fields in the entity.', + ])->addOption('fields', [ + 'help' => 'A comma separated list of fields to make accessible.', + ])->addOption('no-hidden', [ + 'boolean' => true, + 'help' => 'Disable generating hidden fields in the entity.', + ])->addOption('hidden', [ + 'help' => 'A comma separated list of fields to hide.', + ])->addOption('primary-key', [ + 'help' => 'The primary key if you would like to manually set one.' . + ' Can be a comma separated list if you are using a composite primary key.', + ])->addOption('display-field', [ + 'help' => 'The displayField if you would like to choose one.', + ])->addOption('no-test', [ + 'boolean' => true, + 'help' => 'Do not generate a test case skeleton.', + ])->addOption('no-fixture', [ + 'boolean' => true, + 'help' => 'Do not generate a test fixture skeleton.', + ])->setEpilog( + 'Omitting all arguments and options will list the table names you can generate models for.' + ); + + return $parser; + } + + /** + * Interact with FixtureTask to automatically bake fixtures when baking models. + * + * @param string $className Name of class to bake fixture for + * @param string $useTable Optional table name for fixture to use. + * @param \Cake\Console\Arguments $args Arguments instance + * @param \Cake\Console\ConsoleIo $io ConsoleIo instance + * @return void + */ + public function bakeFixture( + string $className, + string $useTable, + Arguments $args, + ConsoleIo $io + ): void { + if ($args->getOption('no-fixture')) { + return; + } + $fixture = new FixtureCommand(); + $fixtureArgs = new Arguments( + [$className], + ['table' => $useTable] + $args->getOptions(), + ['name'] + ); + $fixture->execute($fixtureArgs, $io); + } + + /** + * Assembles and writes a unit test file + * + * @param string $className Model class name + * @param \Cake\Console\Arguments $args Arguments instance + * @param \Cake\Console\ConsoleIo $io ConsoleIo instance + * @return void + */ + public function bakeTest(string $className, Arguments $args, ConsoleIo $io): void + { + if ($args->getOption('no-test')) { + return; + } + $test = new TestCommand(); + $testArgs = new Arguments( + ['table', $className], + $args->getOptions(), + ['type', 'name'] + ); + $test->execute($testArgs, $io); + } +} diff --git a/app/vendor/cakephp/bake/src/Command/PluginCommand.php b/app/vendor/cakephp/bake/src/Command/PluginCommand.php new file mode 100644 index 000000000..9cc30f277 --- /dev/null +++ b/app/vendor/cakephp/bake/src/Command/PluginCommand.php @@ -0,0 +1,434 @@ +path = current(App::path('plugins')); + } + + /** + * Execute the command. + * + * @param \Cake\Console\Arguments $args The command arguments. + * @param \Cake\Console\ConsoleIo $io The console io + * @return int|null The exit code or null for success + */ + public function execute(Arguments $args, ConsoleIo $io): ?int + { + $name = $args->getArgument('name'); + if (empty($name)) { + $io->err('You must provide a plugin name in CamelCase format.'); + $io->err('To make an "MyExample" plugin, run `cake bake plugin MyExample`.'); + + return static::CODE_ERROR; + } + $parts = explode('/', $name); + $plugin = implode('/', array_map([Inflector::class, 'camelize'], $parts)); + + $pluginPath = $this->_pluginPath($plugin); + if (is_dir($pluginPath)) { + $io->out(sprintf('Plugin: %s already exists, no action taken', $plugin)); + $io->out(sprintf('Path: %s', $pluginPath)); + + return static::CODE_ERROR; + } + if (!$this->bake($plugin, $args, $io)) { + $io->error(sprintf('An error occurred trying to bake: %s in %s', $plugin, $this->path . $plugin)); + $this->abort(); + } + + return static::CODE_SUCCESS; + } + + /** + * Bake the plugin's contents + * + * Also update the autoloader and the root composer.json file if it can be found + * + * @param string $plugin Name of the plugin in CamelCased format + * @param \Cake\Console\Arguments $args The command arguments. + * @param \Cake\Console\ConsoleIo $io The console io + * @return bool|null + */ + public function bake(string $plugin, Arguments $args, ConsoleIo $io): ?bool + { + $pathOptions = App::path('plugins'); + if (count($pathOptions) > 1) { + $this->findPath($pathOptions, $io); + } + $io->out(sprintf('Plugin Name: %s', $plugin)); + $io->out(sprintf('Plugin Directory: %s', $this->path . $plugin)); + $io->hr(); + + $looksGood = $io->askChoice('Look okay?', ['y', 'n', 'q'], 'y'); + + if (strtolower($looksGood) !== 'y') { + return null; + } + + $this->_generateFiles($plugin, $this->path, $args, $io); + + $this->_modifyAutoloader($plugin, $this->path, $args, $io); + $this->_modifyApplication($plugin, $io); + + $io->hr(); + $io->out(sprintf('Created: %s in %s', $plugin, $this->path . $plugin), 2); + + $emptyFile = $this->path . '.gitkeep'; + $this->deleteEmptyFile($emptyFile, $io); + + return true; + } + + /** + * Modify the application class + * + * @param string $plugin Name of plugin the plugin. + * @param \Cake\Console\ConsoleIo $io ConsoleIo + * @return void + */ + protected function _modifyApplication(string $plugin, ConsoleIo $io): void + { + $this->executeCommand(PluginLoadCommand::class, [$plugin], $io); + } + + /** + * Generate all files for a plugin + * + * Find the first path which contains `src/Template/Bake/Plugin` that contains + * something, and use that as the template to recursively render a plugin's + * contents. Allows the creation of a bake them containing a `Plugin` folder + * to provide customized bake output for plugins. + * + * @param string $pluginName the CamelCase name of the plugin + * @param string $path the path to the plugins dir (the containing folder) + * @param \Cake\Console\Arguments $args CLI arguments. + * @param \Cake\Console\ConsoleIo $io The io instance. + * @return void + */ + protected function _generateFiles( + string $pluginName, + string $path, + Arguments $args, + ConsoleIo $io + ): void { + $namespace = str_replace('/', '\\', $pluginName); + $baseNamespace = Configure::read('App.namespace'); + + $name = $pluginName; + $vendor = 'your-name-here'; + if (strpos($pluginName, '/') !== false) { + [$vendor, $name] = explode('/', $pluginName); + } + $package = Inflector::dasherize($vendor) . '/' . Inflector::dasherize($name); + + /** @psalm-suppress UndefinedConstant */ + $composerConfig = json_decode( + file_get_contents(ROOT . DS . 'composer.json'), + true + ); + + $renderer = new TemplateRenderer($args->getOption('theme')); + $renderer->set([ + 'package' => $package, + 'namespace' => $namespace, + 'baseNamespace' => $baseNamespace, + 'plugin' => $pluginName, + 'routePath' => Inflector::dasherize($pluginName), + 'path' => $path, + 'root' => ROOT, + 'cakeVersion' => $composerConfig['require']['cakephp/cakephp'], + ]); + + $root = $path . $pluginName . DS; + + $paths = []; + if ($args->hasOption('theme')) { + $paths[] = Plugin::templatePath($args->getOption('theme')); + } + + $paths = array_merge($paths, Configure::read('App.paths.templates')); + $paths[] = Plugin::templatePath('Bake'); + + $fs = new Filesystem(); + $templates = []; + do { + $templatesPath = array_shift($paths) . BakeView::BAKE_TEMPLATE_FOLDER . '/Plugin'; + if (is_dir($templatesPath)) { + $templates = array_keys(iterator_to_array( + $fs->findRecursive($templatesPath, '/.*\.(twig|php)/') + )); + } + } while (!$templates); + + sort($templates); + foreach ($templates as $template) { + $template = substr($template, strrpos($template, 'Plugin' . DIRECTORY_SEPARATOR) + 7, -4); + $template = rtrim($template, '.'); + $this->_generateFile($renderer, $template, $root, $io); + } + } + + /** + * Generate a file + * + * @param \Bake\Utility\TemplateRenderer $renderer The renderer to use. + * @param string $template The template to render + * @param string $root The path to the plugin's root + * @param \Cake\Console\ConsoleIo $io The io instance. + * @return void + */ + protected function _generateFile( + TemplateRenderer $renderer, + string $template, + string $root, + ConsoleIo $io + ): void { + $io->out(sprintf('Generating %s file...', $template)); + $out = $renderer->generate('Bake.Plugin/' . $template); + $io->createFile($root . $template, $out); + } + + /** + * Modifies App's composer.json to include the plugin and tries to call + * composer dump-autoload to refresh the autoloader cache + * + * @param string $plugin Name of plugin + * @param string $path The path to save the phpunit.xml file to. + * @param \Cake\Console\Arguments $args The Arguments instance. + * @param \Cake\Console\ConsoleIo $io The io instance. + * @return bool True if composer could be modified correctly + */ + protected function _modifyAutoloader( + string $plugin, + string $path, + Arguments $args, + ConsoleIo $io + ): bool { + $file = $this->_rootComposerFilePath(); + + if (!file_exists($file)) { + $io->out(sprintf('Main composer file %s not found', $file)); + + return false; + } + + $autoloadPath = str_replace(ROOT . DS, '', $this->path); + $autoloadPath = str_replace('\\', '/', $autoloadPath); + $namespace = str_replace('/', '\\', $plugin); + + $config = json_decode(file_get_contents($file), true); + $config['autoload']['psr-4'][$namespace . '\\'] = $autoloadPath . $plugin . '/src/'; + $config['autoload-dev']['psr-4'][$namespace . '\\Test\\'] = $autoloadPath . $plugin . '/tests/'; + + $io->out('Modifying composer autoloader'); + + $out = json_encode($config, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . "\n"; + $io->createFile($file, $out, (bool)$args->getOption('force')); + + $composer = $this->findComposer($args, $io); + + if (!$composer) { + $io->error('Could not locate composer. Add composer to your PATH, or use the --composer option.'); + $this->abort(); + } + + try { + $cwd = getcwd(); + + // Windows makes running multiple commands at once hard. + chdir(dirname($this->_rootComposerFilePath())); + $command = 'php ' . escapeshellarg($composer) . ' dump-autoload'; + $process = new Process($io); + $io->out($process->call($command)); + + chdir($cwd); + } catch (\RuntimeException $e) { + $error = $e->getMessage(); + $io->error(sprintf('Could not run `composer dump-autoload`: %s', $error)); + $this->abort(); + } + + return true; + } + + /** + * The path to the main application's composer file + * + * This is a test isolation wrapper + * + * @return string the abs file path + */ + protected function _rootComposerFilePath(): string + { + return ROOT . DS . 'composer.json'; + } + + /** + * find and change $this->path to the user selection + * + * @param array $pathOptions The list of paths to look in. + * @param \Cake\Console\ConsoleIo $io The io object + * @return void + */ + public function findPath(array $pathOptions, ConsoleIo $io): void + { + $valid = false; + foreach ($pathOptions as $i => $path) { + if (!is_dir($path)) { + unset($pathOptions[$i]); + } + } + $pathOptions = array_values($pathOptions); + $max = count($pathOptions); + + if ($max === 0) { + $io->error('No valid plugin paths found! Please configure a plugin path that exists.'); + $this->abort(); + } + + if ($max === 1) { + $this->path = $pathOptions[0]; + + return; + } + + $choice = 0; + while (!$valid) { + foreach ($pathOptions as $i => $option) { + $io->out($i + 1 . '. ' . $option); + } + $prompt = 'Choose a plugin path from the paths above.'; + $choice = (int)$io->ask($prompt); + if ($choice > 0 && $choice <= $max) { + $valid = true; + } + } + $this->path = $pathOptions[$choice - 1]; + } + + /** + * Gets the option parser instance and configures it. + * + * @param \Cake\Console\ConsoleOptionParser $parser The option parser + * @return \Cake\Console\ConsoleOptionParser + */ + public function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser + { + $parser->setDescription( + 'Create the directory structure, AppController class and testing setup for a new plugin. ' . + 'Can create plugins in any of your bootstrapped plugin paths.' + )->addArgument('name', [ + 'help' => 'CamelCased name of the plugin to create.', + ])->addOption('composer', [ + 'default' => ROOT . DS . 'composer.phar', + 'help' => 'The path to the composer executable.', + ])->addOption('force', [ + 'short' => 'f', + 'boolean' => true, + 'help' => 'Force overwriting existing files without prompting.', + ])->addOption('theme', [ + 'short' => 't', + 'help' => 'The theme to use when baking code.', + 'default' => Configure::read('Bake.theme') ?? '', + 'choices' => $this->_getBakeThemes(), + ]); + + return $parser; + } + + /** + * Uses either the CLI option or looks in $PATH and cwd for composer. + * + * @param \Cake\Console\Arguments $args The command arguments. + * @param \Cake\Console\ConsoleIo $io The console io + * @return string|bool Either the path to composer or false if it cannot be found. + */ + public function findComposer(Arguments $args, ConsoleIo $io) + { + if ($args->hasOption('composer')) { + /** @var string $path */ + $path = $args->getOption('composer'); + if (file_exists($path)) { + return $path; + } + } + $composer = false; + $path = env('PATH'); + if (!empty($path)) { + $paths = explode(PATH_SEPARATOR, $path); + $composer = $this->_searchPath($paths, $io); + } + + return $composer; + } + + /** + * Search the $PATH for composer. + * + * @param array $path The paths to search. + * @param \Cake\Console\ConsoleIo $io The console io + * @return string|bool + */ + protected function _searchPath(array $path, ConsoleIo $io) + { + $composer = ['composer.phar', 'composer']; + foreach ($path as $dir) { + foreach ($composer as $cmd) { + if (is_file($dir . DS . $cmd)) { + $io->verbose('Found composer executable in ' . $dir); + + return $dir . DS . $cmd; + } + } + } + + return false; + } +} diff --git a/app/vendor/cakephp/bake/src/Command/ShellHelperCommand.php b/app/vendor/cakephp/bake/src/Command/ShellHelperCommand.php new file mode 100644 index 000000000..19f8d5d3f --- /dev/null +++ b/app/vendor/cakephp/bake/src/Command/ShellHelperCommand.php @@ -0,0 +1,54 @@ + + */ + public function templateData(Arguments $arguments): array + { + $namespace = Configure::read('App.namespace'); + if ($this->plugin) { + $namespace = $this->_pluginNamespace($this->plugin); + } + + return ['namespace' => $namespace]; + } + + /** + * Execute the command. + * + * @param \Cake\Console\Arguments $args The command arguments. + * @param \Cake\Console\ConsoleIo $io The console io + * @return int|null The exit code or null for success + */ + public function execute(Arguments $args, ConsoleIo $io): ?int + { + $this->extractCommonProperties($args); + $name = $args->getArgumentAt(0); + if (empty($name)) { + $io->err('You must provide a name to bake a ' . $this->name()); + $this->abort(); + + return null; + } + $name = $this->_getName($name); + $name = Inflector::camelize($name); + $this->bake($name, $args, $io); + $this->bakeTest($name, $args, $io); + + return static::CODE_SUCCESS; + } + + /** + * Generate a class stub + * + * @param string $name The class name + * @param \Cake\Console\Arguments $args The console arguments + * @param \Cake\Console\ConsoleIo $io The console io + * @return void + */ + protected function bake(string $name, Arguments $args, ConsoleIo $io): void + { + $renderer = new TemplateRenderer($args->getOption('theme')); + $renderer->set('name', $name); + $renderer->set($this->templateData($args)); + $contents = $renderer->generate($this->template()); + + $filename = $this->getPath($args) . $this->fileName($name); + $io->createFile($filename, $contents, (bool)$args->getOption('force')); + + $emptyFile = $this->getPath($args) . '.gitkeep'; + $this->deleteEmptyFile($emptyFile, $io); + } + + /** + * Generate a test case. + * + * @param string $className The class to bake a test for. + * @param \Cake\Console\Arguments $args The console arguments + * @param \Cake\Console\ConsoleIo $io The console io + * @return void + */ + public function bakeTest(string $className, Arguments $args, ConsoleIo $io): void + { + if ($args->getOption('no-test')) { + return; + } + $test = new TestCommand(); + $test->plugin = $this->plugin; + $test->bake($this->name(), $className, $args, $io); + } + + /** + * Gets the option parser instance and configures it. + * + * @param \Cake\Console\ConsoleOptionParser $parser Option parser to update. + * @return \Cake\Console\ConsoleOptionParser + */ + public function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser + { + $parser = $this->_setCommonOptions($parser); + $name = $this->name(); + $parser->setDescription( + sprintf('Bake a %s class file.', $name) + )->addArgument('name', [ + 'help' => sprintf( + 'Name of the %s to bake. Can use Plugin.name to bake %s files into plugins.', + $name, + $name + ), + ])->addOption('no-test', [ + 'boolean' => true, + 'help' => 'Do not generate a test skeleton.', + ]); + + return $parser; + } +} diff --git a/app/vendor/cakephp/bake/src/Command/TemplateAllCommand.php b/app/vendor/cakephp/bake/src/Command/TemplateAllCommand.php new file mode 100644 index 000000000..9d2aae179 --- /dev/null +++ b/app/vendor/cakephp/bake/src/Command/TemplateAllCommand.php @@ -0,0 +1,96 @@ +templateCommand = new TemplateCommand(); + } + + /** + * Execute the command. + * + * @param \Cake\Console\Arguments $args The command arguments. + * @param \Cake\Console\ConsoleIo $io The console io + * @return int The exit code + */ + public function execute(Arguments $args, ConsoleIo $io): int + { + $this->extractCommonProperties($args); + /** @var \Cake\Database\Connection $connection */ + $connection = ConnectionManager::get($this->connection); + $scanner = new TableScanner($connection); + + foreach ($scanner->listUnskipped() as $table) { + $templateArgs = new Arguments([$table], $args->getOptions(), ['name']); + $this->templateCommand->execute($templateArgs, $io); + } + + return static::CODE_SUCCESS; + } + + /** + * Gets the option parser instance and configures it. + * + * @param \Cake\Console\ConsoleOptionParser $parser The option parser to update. + * @return \Cake\Console\ConsoleOptionParser + */ + public function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser + { + $parser = $this->_setCommonOptions($parser); + $parser + ->setDescription('Bake all view template files.') + ->addOption('prefix', [ + 'help' => 'The routing prefix to generate views for.', + ])->addOption('index-columns', [ + 'help' => 'Limit for the number of index columns', + 'default' => 0, + ]); + + return $parser; + } +} diff --git a/app/vendor/cakephp/bake/src/Command/TemplateCommand.php b/app/vendor/cakephp/bake/src/Command/TemplateCommand.php new file mode 100644 index 000000000..bb8bfd905 --- /dev/null +++ b/app/vendor/cakephp/bake/src/Command/TemplateCommand.php @@ -0,0 +1,435 @@ +path = current(App::path('templates')); + } + + /** + * Execute the command. + * + * @param \Cake\Console\Arguments $args The command arguments. + * @param \Cake\Console\ConsoleIo $io The console io + * @return int|null The exit code or null for success + */ + public function execute(Arguments $args, ConsoleIo $io): ?int + { + $this->extractCommonProperties($args); + $name = $args->getArgument('name') ?? ''; + $name = $this->_getName($name); + + if (empty($name)) { + $io->out('Possible tables to bake view templates for based on your current database:'); + /** @var \Cake\Database\Connection $connection */ + $connection = ConnectionManager::get($this->connection); + $scanner = new TableScanner($connection); + foreach ($scanner->listUnskipped() as $table) { + $io->out('- ' . $this->_camelize($table)); + } + + return static::CODE_SUCCESS; + } + $template = $args->getArgument('template'); + $action = $args->getArgument('action'); + + $controller = $args->getOption('controller'); + $this->controller($args, $name, $controller); + $this->model($name); + + if ($template && $action === null) { + $action = $template; + } + if ($template) { + $this->bake($args, $io, $template, true, $action); + + return static::CODE_SUCCESS; + } + + $vars = $this->_loadController($io); + $methods = $this->_methodsToBake(); + + foreach ($methods as $method) { + try { + $content = $this->getContent($args, $io, $method, $vars); + $this->bake($args, $io, $method, $content); + } catch (MissingTemplateException $e) { + $io->verbose($e->getMessage()); + } catch (RuntimeException $e) { + $io->error($e->getMessage()); + } + } + + return static::CODE_SUCCESS; + } + + /** + * Set the model class for the table. + * + * @param string $table The table/model that is being baked. + * @return void + */ + public function model(string $table): void + { + $tableName = $this->_camelize($table); + $plugin = $this->plugin; + if ($plugin) { + $plugin = $plugin . '.'; + } + $this->modelName = $plugin . $tableName; + } + + /** + * Set the controller related properties. + * + * @param \Cake\Console\Arguments $args The arguments + * @param string $table The table/model that is being baked. + * @param string|null $controller The controller name if specified. + * @return void + */ + public function controller(Arguments $args, string $table, ?string $controller = null): void + { + $tableName = $this->_camelize($table); + if (empty($controller)) { + $controller = $tableName; + } + $this->controllerName = $controller; + + $plugin = $this->plugin; + if ($plugin) { + $plugin .= '.'; + } + $prefix = $this->getPrefix($args); + if ($prefix) { + $prefix .= '/'; + } + $this->controllerClass = (string)App::className($plugin . $prefix . $controller, 'Controller', 'Controller'); + } + + /** + * Get the path base for view templates. + * + * @param \Cake\Console\Arguments $args The arguments + * @param string|null $container Unused. + * @return string + */ + public function getTemplatePath(Arguments $args, ?string $container = null): string + { + $path = parent::getTemplatePath($args, $container); + $path .= $this->controllerName . DS; + + return $path; + } + + /** + * Get a list of actions that can / should have view templates baked for them. + * + * @return string[] Array of action names that should be baked + */ + protected function _methodsToBake(): array + { + $base = Configure::read('App.namespace'); + + $methods = []; + if (class_exists($this->controllerClass)) { + $methods = array_diff( + array_map( + 'Cake\Utility\Inflector::underscore', + get_class_methods($this->controllerClass) + ), + array_map( + 'Cake\Utility\Inflector::underscore', + get_class_methods($base . '\Controller\AppController') + ) + ); + } + if (empty($methods)) { + $methods = $this->scaffoldActions; + } + foreach ($methods as $i => $method) { + if ($method[0] === '_') { + unset($methods[$i]); + } + } + + return $methods; + } + + /** + * Loads Controller and sets variables for the template + * Available template variables: + * + * - 'modelObject' + * - 'modelClass' + * - 'entityClass' + * - 'primaryKey' + * - 'displayField' + * - 'singularVar' + * - 'pluralVar' + * - 'singularHumanName' + * - 'pluralHumanName' + * - 'fields' + * - 'keyFields' + * - 'schema' + * + * @param \Cake\Console\ConsoleIo $io Instance of the ConsoleIO + * @return array Returns variables to be made available to a view template + */ + protected function _loadController(ConsoleIo $io): array + { + if ($this->getTableLocator()->exists($this->modelName)) { + $modelObject = $this->getTableLocator()->get($this->modelName); + } else { + $modelObject = $this->getTableLocator()->get($this->modelName, [ + 'connectionName' => $this->connection, + ]); + } + + $namespace = Configure::read('App.namespace'); + + $primaryKey = $displayField = $singularVar = $singularHumanName = null; + $schema = $fields = $modelClass = null; + try { + $primaryKey = (array)$modelObject->getPrimaryKey(); + $displayField = $modelObject->getDisplayField(); + $singularVar = $this->_singularName($this->controllerName); + $singularHumanName = $this->_singularHumanName($this->controllerName); + $schema = $modelObject->getSchema(); + $fields = $schema->columns(); + $modelClass = $this->modelName; + } catch (\Exception $exception) { + $io->error($exception->getMessage()); + $this->abort(); + } + + [, $entityClass] = namespaceSplit($this->_entityName($this->modelName)); + $entityClass = sprintf('%s\Model\Entity\%s', $namespace, $entityClass); + if (!class_exists($entityClass)) { + $entityClass = EntityInterface::class; + } + $associations = $this->_filteredAssociations($modelObject); + $keyFields = []; + if (!empty($associations['BelongsTo'])) { + foreach ($associations['BelongsTo'] as $assoc) { + $keyFields[$assoc['foreignKey']] = $assoc['variable']; + } + } + + $pluralVar = Inflector::variable($this->controllerName); + $pluralHumanName = $this->_pluralHumanName($this->controllerName); + + return compact( + 'modelObject', + 'modelClass', + 'entityClass', + 'schema', + 'primaryKey', + 'displayField', + 'singularVar', + 'pluralVar', + 'singularHumanName', + 'pluralHumanName', + 'fields', + 'associations', + 'keyFields', + 'namespace' + ); + } + + /** + * Assembles and writes bakes the view file. + * + * @param \Cake\Console\Arguments $args CLI arguments + * @param \Cake\Console\ConsoleIo $io Console io + * @param string $template Template file to use. + * @param string|true $content Content to write. + * @param string $outputFile The output file to create. If null will use `$template` + * @return void + */ + public function bake( + Arguments $args, + ConsoleIo $io, + string $template, + $content = '', + ?string $outputFile = null + ): void { + if ($outputFile === null) { + $outputFile = $template; + } + if ($content === true) { + $content = $this->getContent($args, $io, $template); + } + if (empty($content)) { + $io->err("No generated content for '{$template}.php', not generating template."); + + return; + } + $path = $this->getTemplatePath($args); + $filename = $path . Inflector::underscore($outputFile) . '.php'; + + $io->out("\n" . sprintf('Baking `%s` view template file...', $outputFile), 1, ConsoleIo::QUIET); + $io->createFile($filename, $content, $args->getOption('force')); + } + + /** + * Builds content from template and variables + * + * @param \Cake\Console\Arguments $args The CLI arguments + * @param \Cake\Console\ConsoleIo $io The console io + * @param string $action name to generate content to + * @param array|null $vars passed for use in templates + * @return string|false Content from template + */ + public function getContent(Arguments $args, ConsoleIo $io, string $action, ?array $vars = null) + { + if (!$vars) { + $vars = $this->_loadController($io); + } + + if (empty($vars['primaryKey'])) { + $io->error('Cannot generate views for models with no primary key'); + $this->abort(); + } + + $renderer = new TemplateRenderer($args->getOption('theme')); + $renderer->set('action', $action); + $renderer->set('plugin', $this->plugin); + $renderer->set($vars); + + $indexColumns = 0; + if ($action === 'index' && $args->getOption('index-columns') !== null) { + $indexColumns = $args->getOption('index-columns'); + } + $renderer->set('indexColumns', $indexColumns); + + return $renderer->generate("Bake.Template/$action"); + } + + /** + * Gets the option parser instance and configures it. + * + * @param \Cake\Console\ConsoleOptionParser $parser The option parser to update. + * @return \Cake\Console\ConsoleOptionParser + */ + public function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser + { + $parser = $this->_setCommonOptions($parser); + + $parser->setDescription( + 'Bake views for a controller, using built-in or custom templates. ' + )->addArgument('name', [ + 'help' => 'Name of the controller views to bake. You can use Plugin.name as a shortcut for plugin baking.', + ])->addArgument('template', [ + 'help' => "Will bake a single action's file. core templates are (index, add, edit, view)", + ])->addArgument('action', [ + 'help' => 'Will bake the template in