Cómo superar una prueba técnica PHP - segunda parte
Tags: programming, php, testing
Published: 2021-08-23 18:34:30

Una vez definido nuestro directorio de trabajo y configurado nuestro composer.json, debemos crear las interfaces
necesarias, esto es:
```php
namespace App\Interfaces;

interface MovieDispatcherInterface
{
    public function match(): void;

    public function addTask(MovieInterface $movie): void;

    public function removeTask(MovieInterface $movie): void;

    public function movies(): array;
}
```

Necesitaremos una clase que encapsule las reglas discriminatorias de manera escalables. Utilizaremos en esta clase el principio **Open/Close**.

```php
namespace App\Interfaces;

interface RuleInterface
{
    // map some items from a array
    public function map(array $arrayElements) : array ;
}
```
Y por último la interfaz con los métodos a implementar para las películas:

```php
namespace App\Interfaces;

interface MovieInterface
{
    public function id(): int;

    public function prioridad(): float;

    public function titulo(): string;

    public function estreno(): bool;

    public function descripcion(): string;
}
```

Una variante de la prueba técnica, consiste en que ya tienes el código preparado. Tan sólo tienes que crear las clases que te solicitan. En esta variante, es muy posible que tengas que ejecutar tests unitarios.

Una vez diseñados nuestras interfaces, procedemos a construir las clases:
```php
declare(strict_types = 1);

namespace App;

use App\Interfaces\MovieInterface;

class Movie implements MovieInterface
{
    public int $id;

    public float $prioridad;

    public string $titulo;

    public bool $estreno;

    public string $description;

    public function __construct(int $id, string $titulo, bool $estreno, string $description)
    {
        $this->prioridad = 5.00 ;
        $this->id = $id;
        $this->titulo = $titulo;
        $this->estreno = $estreno;
        $this->description = $description;
    }

    public function id() : int
    {
        return $this->id;
    }

    public function prioridad() : float
    {
        return $this->prioridad;
    }
    
    public function titulo() : string
    {
        return $this->titulo;
    }

    public function estreno() : bool
    {
        return $this->estreno;
    }

    public function descripcion() : string
    {
        return $this->description;
    }
}
```
Nuestro contenedor de reglas, que permitirá añadir las reglas discriminatorias para nuestros requerimientos.
La idea, es tener un conjunto de reglas que comparten una interfaz en común, y cada regla discrimina o actualiza
el array de películas de forma diferente. De esta manera podemos "escalar" el código sin modificar su estructura. (Principios SOLID)

```php
declare(strict_types = 1);

namespace App;

class ContainerRulesArrayMap
{
    private $rules = [];

    private $items = [];

    public function __construct(array $tasks)
    {
        $this->items = $tasks;
    }

    public function addRule(Rule $rule) : void
    {
        $this->rules[] = $rule;
    }

    /**
     * execRule
     *
     * run each rule and aply the filter method
     * to each item from array origin
     *
     *
     * @return void
     */

    public function execRule() : void
    {
        foreach ($this->rules as $rule) {
            $this->items = $rule->map($this->items);
        }
    }
}
```
Y nuestro flamante MovieDispatcher:
```php
    declare(strict_types = 1);

    namespace App;

    use App\Interfaces\MovieDispatcherInterface;
    use App\Interfaces\MovieInterface;
    use App\ContainerRulesArrayMap;
    use App\ArrayMap\Titulo;
    use App\ArrayMap\Estreno;
    use App\ArrayMap\Descripcion;

    class MovieDispatcher implements MovieDispatcherInterface
    {
        private array $movies;

        public function addMovie(MovieInterface $movie) : void
        {
            $this->movies[] = $movie;
        }

        public function match() : void
        {
            $rule = new ContainerRulesArrayMap($this->movies);
          
            $rule->addRule(new Titulo());
            $rule->addRule(new Estreno());
            $rule->addRule(new Descripcion());
            $rule->execRule();

            usort($this->movies, function ($a, $b) {
                return $a->prioridad() > $b->prioridad();
            });
        }

        public function movies() : array
        {
            return $this->movies;
        }

        public function removeMovie(MovieInterface $movie) : void
        {
            $this->movies = array_filter($this->movies, function ($c) use ($movie) {
                return $c->id() !== $movie->id();
            });
        }
    }
```
[Parte 3](https://dev.to/robertomanchado/como-superar-una-prueba-tecnica-php-tercera-parte-3m51)

[Parte 1](https://dev.to/robertomanchado/como-superar-una-prueba-tecnica-php-primera-parte-be)