Skip to content

Commit

Permalink
Added support for callback definitions
Browse files Browse the repository at this point in the history
  • Loading branch information
biserantonov authored and ddinchev committed Jul 3, 2021
1 parent 5eeac92 commit e6a525f
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 5 deletions.
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;
}
}
}
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',
];
});

0 comments on commit e6a525f

Please sign in to comment.