Skip to content
This repository has been archived by the owner on Dec 11, 2020. It is now read-only.

Add CakePHP ORM #428

Merged
merged 5 commits into from
Dec 5, 2014
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions src/Faker/ORM/CakePHP/ColumnTypeGuesser.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php

namespace Faker\ORM\CakePHP;

class ColumnTypeGuesser
{
protected $generator;

public function __construct(\Faker\Generator $generator)
{
$this->generator = $generator;
}

public function guessFormat($column, $table)
{
$generator = $this->generator;
$schema = $table->schema();

switch ($schema->columnType($column)) {
case 'boolean':
return function() use ($generator) {
return $generator->boolean;
};
case 'integer':
return function() {
return mt_rand(0, intval('2147483647'));
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not use `randomNumber()?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can change those, I took those directly from here.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The randomFloat formatter and others were probably added after the Propel ORM populator. But they are faster and more robust than using mt_rand() (see their code).

};
case 'biginteger':
return function() {
return mt_rand(0, intval('18446744073709551615'));
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

may break on 32bits systems

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above comment - then Propel would break too?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably...

};
case 'decimal':
case 'float':
return function() {
return mt_rand(0, intval('4294967295')) / mt_rand(1, intval('4294967295'));
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not use randomFloat?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as before.

};
case 'uuid':
return function() {
return \Cake\Utility\String::uuid();
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not use Faker's uuid?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can change that.

};
case 'string':
$columnData = $schema->column($column);
$length = $columnData['length'];
return function () use ($generator, $length) {
return $generator->text($length);
};
case 'text':
return function () use ($generator) {
return $generator->text();
};
case 'date':
case 'datetime':
case 'timestamp':
case 'time':
return function () use ($generator) {
return $generator->datetime();
};

case 'binary':
default:
return null;
}
}

}
117 changes: 117 additions & 0 deletions src/Faker/ORM/CakePHP/EntityPopulator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
<?php

namespace Faker\ORM\CakePHP;

use Cake\ORM\TableRegistry;
use Faker\Guesser\Name as NameGuesser;

class EntityPopulator
{
protected $class;
protected $columnFormatters = [];
protected $modifiers = [];

public function __construct($class)
{
$this->class = $class;
}

public function __get($name)
{
return $this->{$name};
}

public function __set($name, $value)
{
$this->{$name} = $value;
}

public function mergeColumnFormattersWith($columnFormatters)
{
$this->columnFormatters = array_merge($this->columnFormatters, $columnFormatters);
}

public function mergeModifiersWith($modifiers)
{
$this->modifiers = array_merge($this->modifiers, $modifiers);
}

public function guessColumnFormatters($populator)
{
$formatters = [];
$class = $this->class;
$table = TableRegistry::get($class);
$schema = $table->schema();
$pk = $schema->primaryKey();
$guessers = $populator->getGuessers() + ['ColumnTypeGuesser' => new ColumnTypeGuesser($populator->getGenerator())];
$isForeignKey = function ($column) use ($table) {
foreach ($table->associations()->type('BelongsTo') as $assoc) {
if ($column == $assoc->foreignKey()) {
return true;
}
}
return false;
};


foreach ($schema->columns() as $column) {
if ($column == $pk[0] || $isForeignKey($column)) {
continue;
}

foreach ($guessers as $guesser) {
if ($formatter = $guesser->guessFormat($column, $table)) {
$formatters[$column] = $formatter;
break;
}
}
}

return $formatters;
}

public function guessModifiers($populator)
{
$modifiers = [];
$table = TableRegistry::get($this->class);

$belongsTo = $table->associations()->type('BelongsTo');
foreach ($belongsTo as $assoc) {
$modifiers['belongsTo' . $assoc->name()] = function ($data, $insertedEntities) use ($assoc) {
$table = $assoc->target();
$foreignModel = $table->alias();
$foreignKey = $insertedEntities[$foreignModel][array_rand($insertedEntities[$foreignModel])];
$primaryKey = $table->primaryKey();
$data[$assoc->foreignKey()] = $foreignKey;
return $data;
};
}

// TODO check if TreeBehavior attached to modify lft/rgt cols

return $modifiers;
}

public function execute($class, $insertedEntities, $options = [])
{
$table = TableRegistry::get($class);
$entity = $table->newEntity();

foreach ($this->columnFormatters as $column => $format) {
if (!is_null($format)) {
$entity->{$column} = is_callable($format) ? $format($insertedEntities, $table) : $format;
}
}

foreach ($this->modifiers as $modifier) {
$entity = $modifier($entity, $insertedEntities);
}

if (!$entity = $table->save($entity, $options)) {
throw new \RuntimeException("Failed saving $class record");
}

$pk = $table->primaryKey();
return $entity->{$pk};
}
}
85 changes: 85 additions & 0 deletions src/Faker/ORM/CakePHP/Populator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<?php

namespace Faker\ORM\CakePHP;

class Populator
{

protected $generator;
protected $entities = [];
protected $quantities = [];
protected $guessers = [];

public function __construct(\Faker\Generator $generator)
{
$this->generator = $generator;
}

public function getGenerator()
{
return $this->generator;
}

public function getGuessers()
{
return $this->guessers;
}

public function removeGuesser($name)
{
if ($this->guessers[$name]) {
unset($this->guessers[$name]);
}
return $this;
}

public function addGuesser($class)
{
if (!is_object($class)) {
$class = new $class($this->generator);
}

if (!method_exists($class, 'guessFormat')) {
throw new \Exception('Missing required custom guesser method: ' . get_class($class) . '::guessFormat()');
}

$this->guessers[get_class($class)] = $class;
return $this;
}

public function addEntity($entity, $number, $customColumnFormatters = [], $customModifiers = [])
{
if (!$entity instanceof EntityPopulator) {
$entity = new EntityPopulator($entity);
}

$entity->columnFormatters = $entity->guessColumnFormatters($this);
if ($customColumnFormatters) {
$entity->mergeColumnFormattersWith($customColumnFormatters);
}

$entity->modifiers = $entity->guessModifiers($this);
if ($customModifiers) {
$entity->mergeModifiers($customModifiers);
}

$class = $entity->class;
$this->entities[$class] = $entity;
$this->quantities[$class] = $number;
return $this;
}

public function execute($options = [])
{
$insertedEntities = [];

foreach ($this->quantities as $class => $number) {
for ($i = 0; $i < $number; $i++) {
$insertedEntities[$class][] = $this->entities[$class]->execute($class, $insertedEntities, $options);
}
}

return $insertedEntities;
}

}