zero-to-prod / data-model-factory
Build a Factory for Anything
Fund package maintenance!
Github
Installs: 1 335
Dependents: 4
Suggesters: 11
Security: 0
Stars: 1
Watchers: 1
Forks: 0
Open Issues: 0
Requires
- php: >=7.1.0
Requires (Dev)
Suggests
- zero-to-prod/data-model: Transform data into a class.
- zero-to-prod/data-model-helper: Helpers for a DataModel.
- zero-to-prod/transformable: Transform a class into different types.
README
Contents
Introduction
This package is a fresh take on how to set the state of your DTOs in a simple and delightful way.
The API is takes some hints from Laravel's Eloquent Factories, but adds some niceties such as setting state via dot syntax and using the set() helper method on the fly.
This package does not require any other dependencies, allowing you to make a factory for anything.
The examples use the DataModel trait, making easier to build your DTOs, but it is not required.
Requirements
- PHP 7.1 or higher.
Installation
Install the package via Composer:
composer require zero-to-prod/data-model-factory
This will add the package to your project’s dependencies and create an autoloader entry for it.
Additional Packages
- DataModel: Transform data into a class.
- DataModelHelper: Helpers for a
DataModel
. - Transformable: Transform a
DataModel
into different types.
Usage
This example makes use of the DataModel trait to instantiate the User
class.
You can install the DataModel package like this:
composer require zero-to-prod/data-model
If you don't want to use this trait, you can customize the class instantiation this way.
-
Include the Factory trait in your factory class.
-
Set the
$model
property to the class you want to instantiate. -
Implement a
definition()
method that returns an array of default values. -
NOTE: The
$this->state()
method accepts dot syntax, arrays, or a callback.
class User { use \Zerotoprod\DataModelFactory\DataModel; public $first_name; public $last_name; public $address; public static function factory(array $context = []): UserFactory { return new UserFactory($context); } } class UserFactory { use \Zerotoprod\DataModelFactory\Factory; /* This is the class to be instantiated with the make() method */ protected $model = User::class; protected function definition(): array { return [ 'first_name' => 'John', 'last_name' => 'N/A', 'address' => [ 'street' => 'Memory Lane' ] ]; } public function setStreet(string $value): self { /** Dot Syntax */ return $this->state('address.street', $value); } public function setFirstName(string $value): self { /** Array Syntax */ return $this->state(['first_name' => $value]); } public function setLastName(): self { /** Closure Syntax */ return $this->state(function ($context) { return ['first_name' => $context['last_name']]; }); } /* Optionally implement for better static analysis */ public function make(): User { return $this->instantiate(); } } $User = UserFactory::factory([User::last_name => 'Doe']) ->setFirstName('Jane') ->make(); User::factory([User::last_name => 'Doe'])->make(); // Also works for this example echo $User->first_name; // 'Jane' echo $User->last_name; // 'Doe'
Custom Class Instantiation
To customize instantiation, override the make()
method.
class User { public function __construct(public string $fist_name, public string $last_name) { } } class UserFactory { use \Zerotoprod\DataModelFactory\Factory; private function definition(): array { return [ 'first_name' => 'John', 'last_name' => 'Doe', ]; } private function make(): User { return new User($this->context['first_name'], $this->context['last_name']); } } $User = UserFactory::factory()->make(); echo $User->first_name; // 'Jane' echo $User->last_name; // 'Doe'
The set()
Method
You can use the set()
helper method to fluently modify the state of your model in a convenient way.
This is a great way to modify a model without having to implement a method in the factory.
$User = User::factory() ->set('first_name', 'John') ->set(['last_name' => 'Doe']) ->set(function ($context) { return ['surname' => $context['last_name']]; }) ->set('address.postal_code', '46789') // dot syntax for nested values ->make(); echo $User->first_name; // John echo $User->last_name; // Doe echo $User->surname; // Doe echo $User->address->postal_code; // 46789
The merge()
Method
Sometimes it is useful to merge new values into the current context of the factory.
Use the merge()
method to merge any new values and update the factory context.
class UserFactory { use \Zerotoprod\DataModelFactory\Factory; private function definition(): array { return [ 'first_name' => 'John', 'last_name' => 'Doe', ]; } } $User = UserFactory::factory() ->merge(['first_name' => 'Jane']) ->make(); echo $User->first_name; // 'Jane' echo $User->last_name; // 'Doe'
The context()
Method
Use the context()
method to get the context of the factory.
class UserFactory { use \Zerotoprod\DataModelFactory\Factory; private function definition(): array { return [ 'first_name' => 'John', 'last_name' => 'Doe', ]; } } $User = UserFactory::factory()->context(); echo $User['first_name']; // 'John' echo $User['last_name']; // 'Doe'
Contributing
Contributions, issues, and feature requests are welcome! Feel free to check the issues page if you want to contribute.
- Fork the repository.
- Create a new branch (
git checkout -b feature-branch
). - Commit changes (
git commit -m 'Add some feature'
). - Push to the branch (
git push origin feature-branch
). - Create a new Pull Request.