Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for callback definitions #478

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
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
41 changes: 36 additions & 5 deletions src/Definition.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

namespace League\FactoryMuffin;

use League\FactoryMuffin\Exceptions\DefinitionException;

/**
* This is the model definition class.
*
Expand Down Expand Up @@ -50,7 +52,7 @@ final class Definition
/**
* The attribute definitions.
*
* @var array
* @var array|callable
*/
private $definitions = [];

Expand Down Expand Up @@ -176,14 +178,24 @@ public function getCallback()
* Add an attribute definitions.
*
* Note that we're appending to the original attribute definitions here.
* Will throw exception if definitions are already defined by a callback.
*
* @param string $attribute The attribute name.
* @param string|callable $definition The attribute definition.
*
* @throws DefinitionException
*
* @return \League\FactoryMuffin\Definition
*/
public function addDefinition($attribute, $definition)
{
if (is_callable($this->definitions)) {
$message = "Can't add definition for attribute '$attribute'. "
.'Definitions are already defined by a callback.';

throw new DefinitionException($this->class, $message);
}

$this->definitions[$attribute] = $definition;

return $this;
Expand All @@ -195,13 +207,21 @@ public function addDefinition($attribute, $definition)
* Note that we're appending to the original attribute definitions here
* instead of switching them out for the new ones.
*
* @param array $definitions The attribute definitions.
* @param array|callable $definitions The attribute definitions.
*
* @throws \InvalidArgumentException
*
* @return \League\FactoryMuffin\Definition
*/
public function setDefinitions(array $definitions = [])
public function setDefinitions($definitions)
{
$this->definitions = array_merge($this->definitions, $definitions);
if (is_callable($definitions)) {
$this->definitions = $definitions;
} elseif (is_array($definitions)) {
$this->definitions = array_merge($this->definitions, $definitions);
} else {
throw new \InvalidArgumentException('Definitions must be array or callable.');
}

return $this;
}
Expand All @@ -221,10 +241,21 @@ public function clearDefinitions()
/**
* Get the attribute definitions.
*
* @throws DefinitionException
*
* @return array
*/
public function getDefinitions()
{
return $this->definitions;
if (is_callable($this->definitions)) {
$definitions = call_user_func($this->definitions);
if (!is_array($definitions)) {
throw new DefinitionException($this->class, 'Definitions callback must return array.');
}

return $definitions;
} else {
return $this->definitions;
}
}
}
60 changes: 60 additions & 0 deletions src/Generators/FactoryGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,66 @@ class FactoryGenerator extends EntityGenerator
*/
private static $properties = ['id', '_id', 'Id'];

/**
* Set methods for accessing model id.
*
* @param array $methods
*/
public static function setMethods(array $methods)
{
self::$methods = $methods;
}

/**
* Get methods for accessing model id.
*
* @return string[]
*/
public static function getMethods()
{
return self::$methods;
}

/**
* Add method for accessing model id.
*
* @param $method
*/
public static function addMethod($method)
{
self::$methods[] = $method;
}

/**
* Set properties for accessing model id.
*
* @param array $properties
*/
public static function setProperties(array $properties)
{
self::$properties = $properties;
}

/**
* Get properties for accessing model id.
*
* @return string[]
*/
public static function getProperties()
{
return self::$properties;
}

/**
* Add property for accessing model id.
*
* @param $property
*/
public static function addProperty($property)
{
self::$properties[] = $property;
}

/**
* Generate, and return the attribute.
*
Expand Down
3 changes: 3 additions & 0 deletions tests/AbstractTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
*/
abstract class AbstractTestCase extends TestCase
{
/**
* @var FactoryMuffin
*/
protected static $fm;

public static function setupBeforeClass()
Expand Down
58 changes: 58 additions & 0 deletions tests/DefinitionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,64 @@ public function testNoMakerGroup()
$this->assertInstanceOf('CustomMakerStub', $obj);
$this->assertSame('bar', $obj->foo);
}

public function testDefineWithCallback()
{
$user = static::$fm->create('definitionscallback:UserModelStub');

$this->assertInstanceOf('UserModelStub', $user);
$this->assertInternalType('string', $user->name);
$this->assertInternalType('boolean', $user->active);
$this->assertContains('@', $user->email);
}

/**
* @expectedException \InvalidArgumentException
*/
public function testShouldThrowExceptionWhenDefinitionsAreNeitherArrayNorCallback()
{
try {
static::$fm->define('invaliddefinitions:UserModelStub')->setDefinitions('invalid definitions');
} catch (\InvalidArgumentException $e) {
$this->assertSame('Definitions must be array or callable.', $e->getMessage());

throw $e;
}
}

/**
* @expectedException \League\FactoryMuffin\Exceptions\DefinitionException
*/
public function testShouldThrowExceptionWhenDefinitionsCallbakcDoesntReturnArray()
{
try {
$model = 'noarraydefinitions:UserModelStub';

static::$fm->define($model)->setDefinitions(function () {
return 'not an array';
});
static::$fm->getDefinition($model)->getDefinitions();
} catch (\League\FactoryMuffin\Exceptions\DefinitionException $e) {
$this->assertSame('Definitions callback must return array.', $e->getMessage());

throw $e;
}
}

/**
* @expectedException \League\FactoryMuffin\Exceptions\DefinitionException
*/
public function testShouldThrowExceptionWhenDefinitionsAreSetWithCallbackAndTryToAddDefinition()
{
try {
static::$fm->getDefinition('definitionscallback:UserModelStub')->addDefinition('name', 'foo');
} catch (\League\FactoryMuffin\Exceptions\DefinitionException $e) {
$message = "Can't add definition for attribute 'name'. Definitions are already defined by a callback.";
$this->assertSame($message, $e->getMessage());

throw $e;
}
}
}

class AttributeDefinitionsStub
Expand Down
10 changes: 10 additions & 0 deletions tests/factories/definition.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,13 @@
});

$fm->define('clear:CustomMakerStub')->clearMaker();

$fm->define('definitionscallback:UserModelStub')->setDefinitions(function () {
return [
'name' => Faker::word(),
'active' => Faker::boolean(),
'email' => Faker::email(),
'age' => Faker::numberBetween(18, 35),
'profile' => 'factory|ProfileModelStub',
];
});