forked from thephpleague/factory-muffin
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from floriandammeyer/hydration-strategies
Hydration strategies
- Loading branch information
Showing
9 changed files
with
276 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
<?php | ||
|
||
namespace League\FactoryMuffin\HydrationStrategies; | ||
|
||
/** | ||
* Interface for defining strategies to hydrate a model's attributes. | ||
* | ||
* @author Florian Dammeyer <[email protected]> | ||
*/ | ||
interface HydrationStrategyInterface | ||
{ | ||
/** | ||
* Set the attribute with the given key on | ||
* the given object to the given value. | ||
* | ||
* @param object $model The model instance to set the attribute on. | ||
* @param string $key The key of the attribute to be set. | ||
* @param mixed $value The new value for the given attribute. | ||
*/ | ||
public function set($model, $key, $value); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
<?php | ||
|
||
namespace League\FactoryMuffin\HydrationStrategies; | ||
|
||
/** | ||
* A hydration strategy that uses public setter methods | ||
* or alternatively public property access. | ||
* | ||
* This has been the hardcoded way to hydrate models | ||
* before hydration strategies were implemented. | ||
* | ||
* @author Florian Dammeyer <[email protected]> | ||
*/ | ||
class PublicSetterHydrationStrategy implements HydrationStrategyInterface | ||
{ | ||
/** | ||
* Set the given attribute by using a public setter method | ||
* or public property access if possible. | ||
* | ||
* @param object $model | ||
* @param string $key | ||
* @param mixed $value | ||
*/ | ||
public function set($model, $key, $value) | ||
{ | ||
$setter = 'set'.ucfirst(static::camelize($key)); | ||
|
||
// check if there is a setter and use it instead | ||
if (method_exists($model, $setter) && is_callable([$model, $setter])) { | ||
$model->$setter($value); | ||
} else { | ||
$model->$key = $value; | ||
} | ||
} | ||
|
||
/** | ||
* Camelize string. | ||
* | ||
* Transforms a string to camel case (e.g. first_name -> firstName). | ||
* | ||
* @param string $str String in underscore format. | ||
* | ||
* @return string | ||
*/ | ||
protected static function camelize($str) | ||
{ | ||
return preg_replace_callback('/_([a-z0-9])/', function ($c) { | ||
return strtoupper($c[1]); | ||
}, $str); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
<?php | ||
|
||
namespace League\FactoryMuffin\HydrationStrategies; | ||
|
||
use ReflectionProperty; | ||
|
||
/** | ||
* A hydration strategy that uses reflection to change properties directly. | ||
* | ||
* Reflection enables this strategy to set private and protected properties | ||
* without the need of public setter methods. | ||
* | ||
* @author Florian Dammeyer <[email protected]> | ||
*/ | ||
class ReflectionHydrationStrategy implements HydrationStrategyInterface | ||
{ | ||
public function set($model, $key, $value) | ||
{ | ||
$property = new ReflectionProperty(get_class($model), $key); | ||
$property->setAccessible(true); | ||
$property->setValue($model, $value); | ||
$property->setAccessible(false); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
<?php | ||
|
||
use League\FactoryMuffin\HydrationStrategies\PublicSetterHydrationStrategy; | ||
use League\FactoryMuffin\HydrationStrategies\ReflectionHydrationStrategy; | ||
use Prophecy\Argument; | ||
|
||
class HydrationStrategyTest extends AbstractTestCase | ||
{ | ||
public function testHydrationStrategyIsBeingUsed() | ||
{ | ||
$strategy = $this->prophesize('League\FactoryMuffin\HydrationStrategies\HydrationStrategyInterface'); | ||
|
||
static::$fm->setHydrationStrategy('FakerHydrationModel', $strategy->reveal()); | ||
static::$fm->instance('FakerHydrationModel'); | ||
|
||
$strategy->set(Argument::type('FakerHydrationModel'), Argument::type('string'), Argument::any()) | ||
->shouldBeCalledTimes(3); | ||
} | ||
|
||
public function testPublicSetterHydration() | ||
{ | ||
$strategy = new PublicSetterHydrationStrategy(); | ||
|
||
$model = new ModelWithPublicSetters(); | ||
|
||
$strategy->set($model, 'value', 'Test value'); | ||
$strategy->set($model, 'separated_value', 'Another test value'); | ||
|
||
$this->assertEquals($model->getValue(), 'Test value'); | ||
$this->assertEquals($model->getSeparatedValue(), 'Another test value'); | ||
} | ||
|
||
public function testPublicAttributesHydration() | ||
{ | ||
$strategy = new PublicSetterHydrationStrategy(); | ||
|
||
$model = new ModelWithPublicAttributes(); | ||
|
||
$strategy->set($model, 'value', 'Test value'); | ||
$strategy->set($model, 'separated_value', 'Another test value'); | ||
|
||
$this->assertEquals($model->value, 'Test value'); | ||
$this->assertEquals($model->separated_value, 'Another test value'); | ||
} | ||
|
||
public function testProtectedAttributesHydrationByReflection() | ||
{ | ||
$strategy = new ReflectionHydrationStrategy(); | ||
|
||
$model = new ModelWithProtectedAttributes(); | ||
|
||
$strategy->set($model, 'value', 'Test value'); | ||
$strategy->set($model, 'separated_value', 'Another test value'); | ||
|
||
$this->assertEquals($model->getValue(), 'Test value'); | ||
$this->assertEquals($model->getSeparatedValue(), 'Another test value'); | ||
} | ||
} | ||
|
||
class ModelWithPublicAttributes | ||
{ | ||
public $value; | ||
public $separated_value; | ||
} | ||
|
||
class ModelWithProtectedAttributes | ||
{ | ||
protected $value; | ||
protected $separated_value; | ||
|
||
public function getValue() | ||
{ | ||
return $this->value; | ||
} | ||
|
||
public function getSeparatedValue() | ||
{ | ||
return $this->separated_value; | ||
} | ||
} | ||
|
||
class ModelWithPublicSetters extends ModelWithProtectedAttributes | ||
{ | ||
public function setValue($value) | ||
{ | ||
$this->value = $value; | ||
} | ||
|
||
public function setSeparatedValue($separated_value) | ||
{ | ||
$this->separated_value = $separated_value; | ||
} | ||
} | ||
|
||
class FakerHydrationModel | ||
{ | ||
public $title; | ||
public $email; | ||
public $text; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
<?php | ||
|
||
use League\FactoryMuffin\Faker\Facade as Faker; | ||
|
||
/* @var \League\FactoryMuffin\FactoryMuffin $fm */ | ||
$fm->define('FakerHydrationModel')->setDefinitions([ | ||
'title' => Faker::word(), | ||
'email' => Faker::email(), | ||
'text' => Faker::text(), | ||
]); |