Skip to content

Commit

Permalink
Merge pull request #243 from dereuromark/default-data
Browse files Browse the repository at this point in the history
Add smart default data that is required by schema.
pabloelcolombiano authored Feb 8, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
2 parents cfdf91d + 4c7dcbd commit 5d3bfe5
Showing 3 changed files with 185 additions and 3 deletions.
151 changes: 151 additions & 0 deletions src/Command/BakeFixtureFactoryCommand.php
Original file line number Diff line number Diff line change
@@ -19,6 +19,7 @@
use Cake\Console\ConsoleIo;
use Cake\Console\ConsoleOptionParser;
use Cake\Core\Configure;
use Cake\ORM\AssociationCollection;
use Cake\ORM\Table;
use Cake\ORM\TableRegistry;
use Cake\Utility\Hash;
@@ -47,6 +48,35 @@ class BakeFixtureFactoryCommand extends BakeCommand
*/
private Table $table;

/**
* @var array
*/
protected array $map = [
'string' => [
'name' => 'name',
'first_name' => 'firstName',
'last_name' => 'lastName',
'username' => 'userName',
'slug' => 'slug',
'email' => 'email',
'description' => 'words',
'postal_code' => 'postcode',
'city' => 'city',
'address' => 'address',
'url' => 'url',
'ip_address' => 'ipv4',
'currency' => 'currencyCode',
'phone_number' => 'phoneNumber',
'timezone' => 'timezone',
],
'float' => [
'latitude' => 'latitude',
'longitude' => 'longitude',
],
'integer' => [
],
];

/**
* @return string Name of the command
*/
@@ -271,6 +301,7 @@ public function bakeFixtureFactory(string $modelName, Arguments $args, ConsoleIo

$renderer = new TemplateRenderer('CakephpFixtureFactories');
$renderer->set($this->templateData($args));
$renderer->viewBuilder()->addHelper('CakephpFixtureFactories.FactoryBake');

$contents = $renderer->generate($this->template());

@@ -294,6 +325,7 @@ public function templateData(Arguments $arg): array
'modelName' => $this->modelName,
'factory' => Inflector::singularize($this->modelName) . 'Factory',
'namespace' => $this->getFactoryNamespace($this->plugin),
'defaultData' => $this->defaultData(),
];
$useStatements = $methods = [];
if ($arg->getOption('methods')) {
@@ -458,4 +490,123 @@ public function getOptionParser(): ConsoleOptionParser

return $parser;
}

/**
* @return array<string, mixed>
*/
protected function defaultData(): array
{
$defaultData = [];

$modelName = $this->getTable()->getAlias();
$schema = $this->getTable()->getSchema();
$columns = $schema->columns();
$foreignKeys = $this->foreignKeys($this->getTable()->associations());
foreach ($columns as $column) {
$keys = $schema->getPrimaryKey();
if (in_array($column, $keys, true) || in_array($column, $foreignKeys, true)) {
continue;
}

$columnSchema = $schema->getColumn($column);
if ($columnSchema['null'] || $columnSchema['default'] !== null) {
continue;
}

if (!in_array($columnSchema['type'], ['integer', 'string', 'date', 'datetime', 'time', 'bool', 'float'])) {
continue;
}

$guessedDefault = $this->guessDefault($column, $modelName, $columnSchema);
if ($guessedDefault) {
$defaultData[$column] = $guessedDefault;
}
}

return $defaultData;
}

/**
* @param string $column
* @param string $modelName
* @param array $columnSchema
* @return mixed
*/
protected function guessDefault(string $column, string $modelName, array $columnSchema): mixed
{
$map = array_merge_recursive($this->map, (array)Configure::read('FixtureFactories.defaultDataMap'));
$map = $map[$columnSchema['type']] ?? [];

$modelNameMap = [
'Countries' => 'country',
'Cities' => 'city',
];

if ($columnSchema['type'] === 'string') {
if ($column === 'name' && isset($modelNameMap[$modelName])) {
return '$faker->' . $modelNameMap[$modelName] . '()';
}
if (isset($map[$column])) {
return '$faker->' . $map[$column] . '()';
}

return '$faker->text(' . $columnSchema['length'] . ')';
}
if ($columnSchema['type'] === 'integer') {
if (isset($map[$column])) {
return '$faker->' . $map[$column] . '()';
}

return '$faker->randomNumber()';
}
if ($columnSchema['type'] === 'boolean') {
if (isset($map[$column])) {
return '$faker->' . $map[$column] . '()';
}

return '$faker->boolean()';
}
if ($columnSchema['type'] === 'date') {
if (isset($map[$column])) {
return '$faker->' . $map[$column] . '()';
}

return '$faker->date()';
}
if ($columnSchema['type'] === 'datetime') {
if (isset($map[$column])) {
return '$faker->' . $map[$column] . '()';
}

return '$faker->datetime()';
}
if ($columnSchema['type'] === 'time') {
if (isset($map[$column])) {
return '$faker->' . $map[$column] . '()';
}

return '$faker->time()';
}

return null;
}

/**
* @param \Cake\ORM\AssociationCollection $associations
* @return array<string>
*/
protected function foreignKeys(AssociationCollection $associations): array
{
$keys = [];

foreach ($associations as $association) {
$key = $association->getForeignKey();
if ($key === false) {
continue;
}
$keys = array_merge($keys, (array)$key);
}

return $keys;
}
}
33 changes: 33 additions & 0 deletions src/View/Helper/FactoryBakeHelper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php
declare(strict_types=1);

namespace CakephpFixtureFactories\View\Helper;

use Cake\View\Helper;

class FactoryBakeHelper extends Helper
{
/**
* @param array $defaultData
* @return string
*/
public function defaultData(array $defaultData): string
{
$rows = [];
$indent = str_repeat(' ', 4 * 4);

foreach ($defaultData as $key => $value) {
$rows[] = $indent . '\'' . $key . '\' => ' . $value . ',';
}

$string = implode(PHP_EOL, $rows);

$default = <<<TXT
// set the model's default values
// For example:
// 'name' => \$faker->lastName()
TXT;

return ltrim($string ?: $default);
}
}
4 changes: 1 addition & 3 deletions templates/bake/fixture_factory.twig
Original file line number Diff line number Diff line change
@@ -41,9 +41,7 @@ class {{ factory }} extends CakephpBaseFactory
{
$this->setDefaultData(function (Generator $faker) {
return [
// set the model's default values
// For example:
// 'name' => $faker->lastName
{{ FactoryBake.defaultData(defaultData)|raw }}
];
});
}

0 comments on commit 5d3bfe5

Please sign in to comment.