Danger
This is an outdated documentation please read the new Monofony documentation instead.
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
$ # with phpdbg installed
$ phpdbg -qrr 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
$
$ # with phpdbg installed
$ phpdbg -qrr vendor/bin/phpspec run spec/App/Factory/ArticleFactorySpec.php -n
And be happy with your first error message with red color.
Note
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
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);
}
Warning
Don’t forget to rerun phpspec on each step.
Solve this on your factory¶
# src/Factory/ArticleFactory.php
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
// [...]
function its_creates_articles(): void
{
$article = $this->createNew();
$article->shouldImplement(Article::class);
}
Solve this on your factory¶
# src/Factory/ArticleFactory.php
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
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.
Note
Here you pass a string, but you often need to pass objects on constructor. You just have to add them on arguments of the let method and don’t forget to use typehints.
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
// [...]
/**
* @param CustomerInterface $author
*
* @return Article
*/
public function createForAuthor(CustomerInterface $author): Article
{
$article = $this->createNew();
$article->setAuthor($author);
return $article;
}
And that’s all to specify this simple article factory.