PhpSpec extension points

Post on 10-May-2015

1.089 views 0 download

Tags:

Transcript of PhpSpec extension points

PhpSpec extension pointsfor version 2.0.0

About me PHP Software engineer KrakDevs meetups organizer Huge fan of BDD/TDD Part of Coduo

Web:https://github.com/norzechowicz https://twitter.com/norzechowicz http://coduo.plhttp://krakdevs.plNorbert Orzechowicz

This is everything you need. Trust me ;)

Ok, so how PhpSpec works?

Just like a regular Symfony2 console

application

Read more http://symfony.com/doc/current/components/console/index.html

Ok, but what happens when user execute „run”

command?

$ bin/phpspec run

#!/usr/bin/env php!<?php!//bin/phpspec!!$app = new PhpSpec\Console\Application(PHPSPEC_VERSION);!

Initialize console application<?php!//phpspec/src/PhpSpec/Console/Application.php!!use Symfony\Component\Console\Application as BaseApplication;!!/**! * The command line application entry point! */!class Application extends BaseApplication!{! public function __construct($version)! {! }!}!

Create service container<?php!//phpspec/src/PhpSpec/Console/Application.php!!use Symfony\Component\Console\Application as BaseApplication;!!/**! * The command line application entry point! */!class Application extends BaseApplication!{! public function __construct($version)! {! $this->container = new ServiceContainer;! parent::__construct('phpspec', $version);! }!}!

In the name of dependency injection!

Service Container

<?php!///phpspec/src/PhpSpec/ServiceContainer.php!namespace PhpSpec;!!class ServiceContainer!{! // Sets a object or a callback for the object creation. ! // A new object will be created every time! public function set($id, $value);!! // Sets a object or a callback for the object creation. ! // The same object will be returned every time! public function setShared($id, $callable);!! // Retrieves a service from the container! public function get($id);!! // Retrieves a list of services of a given prefix! public function getByPrefix($prefix);!}!

Explanation of the most important methods

Register service example<?php!///phpspec/src/Acme/MyClass.php!namespace Acme;!!class MyClass!{! public function setup(ServiceContainer $container)! {! $container->set('acme.service.foo', function ($c) {! return new Foo();! });!! $container->setShared('acme.service.bar', function ($c) {! return new Bar();! });!! $container->getByPrefix('acme.service');! // will return acme.service.foo as Foo incance & ! ! ! // acme.service.bar as Bar instance! }!}!

#!/usr/bin/env php!<?php!//bin/phpspec!!$app = new PhpSpec\Console\Application(PHPSPEC_VERSION);!$app->run();!

Run! <?php!//phpspec/src/PhpSpec/Console/Application.php!!use Symfony\Component\Console\Application as BaseApplication;!!/**! * The command line application entry point! */!class Application extends BaseApplication!{! public function doRun(InputInterface $input, OutputInterface $output)! {! $this->setupContainer($this->container); ! }!}!

Not so fast, setup service container first

<?php!//phpspec/src/PhpSpec/Console/Application.php!!use Symfony\Component\Console\Application as BaseApplication;!!class Application extends BaseApplication!{! protected function setupContainer(ServiceContainer $container)! {! $this->setupIO($container);! }!}!

<?php!//phpspec/src/PhpSpec/Console/Application.php!!use Symfony\Component\Console\Application as BaseApplication;!!class Application extends BaseApplication!{! protected function setupContainer(ServiceContainer $container)! {! $this->setupIO($container);! $this->setupEventDispatcher($container);! }!}!

<?php!//phpspec/src/PhpSpec/Console/Application.php!!use Symfony\Component\Console\Application as BaseApplication;!!class Application extends BaseApplication!{! protected function setupContainer(ServiceContainer $container)! {! $this->setupIO($container);! $this->setupEventDispatcher($container);! $this->setupGenerators($container);! }!}!

<?php!//phpspec/src/PhpSpec/Console/Application.php!!use Symfony\Component\Console\Application as BaseApplication;!!class Application extends BaseApplication!{! protected function setupContainer(ServiceContainer $container)! {! $this->setupIO($container);! $this->setupEventDispatcher($container);! $this->setupGenerators($container);! $this->setupPresenter($container);! }!}!

<?php!//phpspec/src/PhpSpec/Console/Application.php!!use Symfony\Component\Console\Application as BaseApplication;!!class Application extends BaseApplication!{! protected function setupContainer(ServiceContainer $container)! {! $this->setupIO($container);! $this->setupEventDispatcher($container);! $this->setupGenerators($container);! $this->setupPresenter($container);! $this->setupLocator($container);! }!}!

<?php!//phpspec/src/PhpSpec/Console/Application.php!!use Symfony\Component\Console\Application as BaseApplication;!!class Application extends BaseApplication!{! protected function setupContainer(ServiceContainer $container)! {! $this->setupIO($container);! $this->setupEventDispatcher($container);! $this->setupGenerators($container);! $this->setupPresenter($container);! $this->setupLocator($container);! $this->setupLoader($container);! }!}!

<?php!//phpspec/src/PhpSpec/Console/Application.php!!use Symfony\Component\Console\Application as BaseApplication;!!class Application extends BaseApplication!{! protected function setupContainer(ServiceContainer $container)! {! $this->setupIO($container);! $this->setupEventDispatcher($container);! $this->setupGenerators($container);! $this->setupPresenter($container);! $this->setupLocator($container);! $this->setupLoader($container);! $this->setupFormatter($container);! }!}!

<?php!//phpspec/src/PhpSpec/Console/Application.php!!use Symfony\Component\Console\Application as BaseApplication;!!class Application extends BaseApplication!{! protected function setupContainer(ServiceContainer $container)! {! $this->setupIO($container);! $this->setupEventDispatcher($container);! $this->setupGenerators($container);! $this->setupPresenter($container);! $this->setupLocator($container);! $this->setupLoader($container);! $this->setupFormatter($container);! $this->setupRunner($container);! }!}!

<?php!//phpspec/src/PhpSpec/Console/Application.php!!use Symfony\Component\Console\Application as BaseApplication;!!class Application extends BaseApplication!{! protected function setupContainer(ServiceContainer $container)! {! $this->setupIO($container);! $this->setupEventDispatcher($container);! $this->setupGenerators($container);! $this->setupPresenter($container);! $this->setupLocator($container);! $this->setupLoader($container);! $this->setupFormatter($container);! $this->setupRunner($container);! $this->setupCommands($container);! }!}!

<?php!//phpspec/src/PhpSpec/Console/Application.php!!use Symfony\Component\Console\Application as BaseApplication;!!class Application extends BaseApplication!{! protected function setupContainer(ServiceContainer $container)! {! $this->setupIO($container);! $this->setupEventDispatcher($container);! $this->setupGenerators($container);! $this->setupPresenter($container);! $this->setupLocator($container);! $this->setupLoader($container);! $this->setupFormatter($container);! $this->setupRunner($container);! $this->setupCommands($container);!! $this->loadConfigurationFile($container);! }!}!

RUN!

<?php!//phpspec/src/PhpSpec/Console/Application.php!!use Symfony\Component\Console\Application as BaseApplication;!!class Application extends BaseApplication!{! public function doRun(InputInterface $input, OutputInterface $output)! {! $this->setupContainer($this->container);! ! foreach ($this->container->getByPrefix('console.commands') as $command) {! $this->add($command);! }! ! return parent::doRun($input, $output);! }!}!

But first add commands. By default „run” and „describe”.

Application is ready what now?

Run command

<?php!//phpspec/src/PhpSpec/Console/Command/RunCommand.php!namespace PhpSpec\Console\Command;!!class RunCommand extends Command!{! protected function configure()! {! // configure input options, arguments, command name! }!! protected function execute(InputInterface $input, OutputInterface $output)! {! // run suite with runner.suite service!! }!}!

There is no magic here, just simple Symfony2 console command.

Suite you say?

Space where specifications exists

Suite

Specifications?

Spaces where examples exists

Suite

FooClassSpec.php - Specification

BarClassSpec.php - Specification

FazClassSpec.php - Specification

BazClassSpec.php - Specification

Examples!?

Yes, functions that describe object behavior (tests)

Suite

FooClassSpec.php - Specification

function it_is_awesome() - Example

function it_do_awesome_stuff() - Example

function it_is_famous() - Example

Make sense now!

Run command simplified algorithm

1. Localize suite - Locator 2. Load suite - Loader 3. Run suite - Suite Runner 4. Run specifications - Specification Runner5. Run examples - Example Runner

And what about extensions?

Remember container setup?

<?php!//phpspec/src/PhpSpec/Console/Application.php!!use Symfony\Component\Console\Application as BaseApplication;!!class Application extends BaseApplication!{! protected function setupContainer(ServiceContainer $container)! {! // . . . ! $this->loadConfigurationFile($container);! }!}!

phpspec.yml suites: acme_suite: namespace: Acme\TheLib spec_prefix: acme_spec ! # shortcut for # my_suite: # namespace: The\Namespace my_suite: The\Namespace !extensions:! - PhpSpec\Symfony2Extension\Extension

Extension interface<?php!//phpspec/src/PhpSpec/Extension/ExtensionInterface.php!namespace PhpSpec\Extension;!!use PhpSpec\ServiceContainer;!!interface ExtensionInterface!{! /**! * @param ServiceContainer $container! */! public function load(ServiceContainer $container);!}!

That’s all?

Simply beautiful, right?

But what can I do with it?

But what can I do with it? Register event listeners as a services Replace existing services Register custom example maintainers Register new fomatters Register new code generators Replace suite locator Register new matchers Register new commands !And many many more…

How?

Let me show you how to register an event listener.

Event subscriber class<?php!///src/Coduo/PhpSpec/Listener/DataProviderListener.php!namespace Coduo\PhpSpec\Listener;!!class DataProviderListener implements EventSubscriberInterface!{! public static function getSubscribedEvents()! {! return array(! 'beforeSpecification' => array('beforeSpecification'),! );! }!! public function beforeSpecification(SpecificationEvent $event)! {! // listener logic here ! }!}!

PhpSpec extension class<?php!//src/Coduo/PhpSpec/DataProviderExtension.php!namespace Coduo\PhpSpec;!!class DataProviderExtension implements ExtensionInterface!{! public function load(ServiceContainer $container)! {! $container->set(! 'event_dispatcher.listeners.data_provider', ! function ($c) {! return new DataProviderListener();! }! );! }!}!

And how PhpSpec know that my service is an

event listener?

Just use proper prefix <?php!//phpspec/src/PhpSpec/Console/Application.php!!use Symfony\Component\Console\Application as BaseApplication;!!class Application extends BaseApplication!{! protected function setupEventDispatcher(ServiceContainer $container)! {! $container->setShared('event_dispatcher', function ($c) {! $dispatcher = new EventDispatcher;!! array_map(! array($dispatcher, 'addSubscriber'),! $c->getByPrefix('event_dispatcher.listeners')! );!! return $dispatcher;! });! }!}!

Are there any other prefixes that I can use?

List of prefixes that you can use by default.

event_dispatcher.listeners - EventSubscriberInterfac code_generator.generators - GeneratorInterfac formatter.presenter.differ.engines - Differ\EngineInterface locator.locators - ResourceLocatorInterface runner.maintaners - MaintainerInterface console.commands - Command

Thank you for your attention

Coduo behaviour driven developers

contact@coduo.pl

Hire us!

Questions?