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.
  • Loading branch information
pabloelcolombiano authored Feb 8, 2024
2 parents cfdf91d + 4c7dcbd commit 5d3bfe5
Show file tree
Hide file tree
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
Expand Up @@ -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;
Expand Down Expand Up @@ -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
*/
Expand Down Expand Up @@ -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());

Expand All @@ -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')) {
Expand Down Expand Up @@ -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
Expand Up @@ -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 }}
];
});
}
Expand Down

0 comments on commit 5d3bfe5

Please sign in to comment.