How to design services with phpspec
Lets configure an Article factory to create an article for an author. This Author implements CustomerInterface.
Generate phpspec for your entity factory
$ vendor/bin/phpspec describe App/Factory/ArticleFactory
Run phpspec and do not fear Red
To run phpspec for our Article factory, run this command:
$ vendor/bin/phpspec run spec/App/Factory/ArticleFactory.php -n
And be happy with your first error message with red color.
You can simply run all the phpspec tests by running vendor/bin/phpspec run -n
Create a minimal article factory class
src/Factory/ArticleFactory.php
<?php
declare(strict_types=1);
namespace App\Factory;
class ArticleFactory
{
}
Rerun phpspec and see a beautiful green color.
Specify it implements sylius factory interface
spec/App/Factory/ArticleFactorySpec.php
function it_implements_sylius_factory_interface(): void
{
$this->shouldImplement(FactoryInterface::class);
}
Solve this on your factory
src/Factory/ArticleFactory.php
<?php
declare(strict_types=1);
namespace App\Factory;
use Sylius\Component\Resource\Factory\FactoryInterface;
class ArticleFactory implements FactoryInterface
{
/**
* {@inheritdoc}
*/
public function createNew()
{
}
}
Specify it creates articles
spec/App/Factory/ArticleFactorySpec.php
<?php
// [...]
function its_creates_articles(): void
{
$article = $this->createNew();
$article->shouldImplement(Article::class);
}
Solve this on your factory
src/Factory/ArticleFactory.php
<?php
declare(strict_types=1);
namespace App\Factory;
use Sylius\Component\Resource\Factory\FactoryInterface;
class ArticleFactory implements FactoryInterface
{
/** @var string */
private $className;
public function __construct(string $className)
{
$this->className = $className;
}
/**
* {@inheritdoc}
*/
public function createNew(): Article
{
return new $this->className();
}
}
Running this step will throw this exception:
exception [err:ArgumentCountError("Too few arguments to function App\Factory\ArticleFactory::__construct(), 0 passed and exactly 1 expected")] has been thrown.
To add arguments on constructor, go back to your factory spec and add these lines:
spec/App/Factory/ArticleFactorySpec.php
<?php
declare(strict_types=1);
namespace spec\App\Factory;
use App\Entity\Article;
use App\Factory\ArticleFactory;
use PhpSpec\ObjectBehavior;
use Sylius\Component\Resource\Factory\FactoryInterface;
class ArticleFactorySpec extends ObjectBehavior
{
function let()
{
$this->beConstructedWith(Article::class);
}
// [...]
}
Rerun phpspec and it should be solved.
Here is an example with object arguments:
function let(FactoryInterface $factory)
{
$this->beConstructedWith($factory);
}
Specify it creates articles for an author
spec/App/Factory/ArticleFactorySpec.php
// [...]
function its_creates_articles_for_an_author(CustomerInterface $author): void
{
$article = $this->createForAuthor($author);
$article->getAuthor()->shouldReturn($author);
}
Add this method on your factory
src/Factory/ArticleFactory.php
// [...]
public function createForAuthor(CustomerInterface $author): Article
{
$article = $this->createNew();
$article->setAuthor($author);
return $article;
}
And that's all to specify this simple article factory.