mirror of
https://github.com/DesignPatternsPHP/DesignPatternsPHP.git
synced 2025-01-18 05:58:16 +01:00
update deps & install rector
This commit is contained in:
parent
04acce6759
commit
579a5ac946
@ -3,9 +3,7 @@ language: php
|
||||
sudo: false
|
||||
|
||||
php:
|
||||
- 7.2
|
||||
- 7.3
|
||||
- 7.4snapshot
|
||||
- 7.4
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
|
@ -3,14 +3,10 @@
|
||||
namespace DesignPatterns\Behavioral\ChainOfResponsibilities;
|
||||
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
abstract class Handler
|
||||
{
|
||||
/**
|
||||
* @var Handler|null
|
||||
*/
|
||||
private $successor = null;
|
||||
private ?Handler $successor = null;
|
||||
|
||||
public function __construct(Handler $handler = null)
|
||||
{
|
||||
@ -20,12 +16,8 @@ abstract class Handler
|
||||
/**
|
||||
* This approach by using a template method pattern ensures you that
|
||||
* each subclass will not forget to call the successor
|
||||
*
|
||||
* @param RequestInterface $request
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
final public function handle(RequestInterface $request)
|
||||
final public function handle(RequestInterface $request): ?string
|
||||
{
|
||||
$processed = $this->processing($request);
|
||||
|
||||
@ -37,5 +29,5 @@ abstract class Handler
|
||||
return $processed;
|
||||
}
|
||||
|
||||
abstract protected function processing(RequestInterface $request);
|
||||
abstract protected function processing(RequestInterface $request): ?string;
|
||||
}
|
||||
|
@ -7,28 +7,16 @@ use Psr\Http\Message\RequestInterface;
|
||||
|
||||
class HttpInMemoryCacheHandler extends Handler
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $data;
|
||||
private array $data;
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param Handler|null $successor
|
||||
*/
|
||||
public function __construct(array $data, Handler $successor = null)
|
||||
public function __construct(array $data, ?Handler $successor = null)
|
||||
{
|
||||
parent::__construct($successor);
|
||||
|
||||
$this->data = $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param RequestInterface $request
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
protected function processing(RequestInterface $request)
|
||||
protected function processing(RequestInterface $request): ?string
|
||||
{
|
||||
$key = sprintf(
|
||||
'%s?%s',
|
||||
|
@ -7,12 +7,7 @@ use Psr\Http\Message\RequestInterface;
|
||||
|
||||
class SlowDatabaseHandler extends Handler
|
||||
{
|
||||
/**
|
||||
* @param RequestInterface $request
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
protected function processing(RequestInterface $request)
|
||||
protected function processing(RequestInterface $request): ?string
|
||||
{
|
||||
// this is a mockup, in production code you would ask a slow (compared to in-memory) DB for the results
|
||||
|
||||
|
@ -5,17 +5,13 @@ namespace DesignPatterns\Behavioral\ChainOfResponsibilities\Tests;
|
||||
use DesignPatterns\Behavioral\ChainOfResponsibilities\Handler;
|
||||
use DesignPatterns\Behavioral\ChainOfResponsibilities\Responsible\HttpInMemoryCacheHandler;
|
||||
use DesignPatterns\Behavioral\ChainOfResponsibilities\Responsible\SlowDatabaseHandler;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
|
||||
class ChainTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var Handler
|
||||
*/
|
||||
private $chain;
|
||||
private Handler $chain;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
|
@ -8,16 +8,11 @@ namespace DesignPatterns\Behavioral\Command;
|
||||
*/
|
||||
class AddMessageDateCommand implements UndoableCommand
|
||||
{
|
||||
/**
|
||||
* @var Receiver
|
||||
*/
|
||||
private $output;
|
||||
private Receiver $output;
|
||||
|
||||
/**
|
||||
* Each concrete command is built with different receivers.
|
||||
* There can be one, many or completely no receivers, but there can be other commands in the parameters.
|
||||
*
|
||||
* @param Receiver $console
|
||||
*/
|
||||
public function __construct(Receiver $console)
|
||||
{
|
||||
|
@ -8,16 +8,11 @@ namespace DesignPatterns\Behavioral\Command;
|
||||
*/
|
||||
class HelloCommand implements Command
|
||||
{
|
||||
/**
|
||||
* @var Receiver
|
||||
*/
|
||||
private $output;
|
||||
private Receiver $output;
|
||||
|
||||
/**
|
||||
* Each concrete command is built with different receivers.
|
||||
* There can be one, many or completely no receivers, but there can be other commands in the parameters
|
||||
*
|
||||
* @param Receiver $console
|
||||
*/
|
||||
public function __construct(Receiver $console)
|
||||
{
|
||||
|
@ -8,16 +8,11 @@ namespace DesignPatterns\Behavioral\Command;
|
||||
*/
|
||||
class Invoker
|
||||
{
|
||||
/**
|
||||
* @var Command
|
||||
*/
|
||||
private $command;
|
||||
private Command $command;
|
||||
|
||||
/**
|
||||
* in the invoker we find this kind of method for subscribing the command
|
||||
* There can be also a stack, a list, a fixed set ...
|
||||
*
|
||||
* @param Command $cmd
|
||||
*/
|
||||
public function setCommand(Command $cmd)
|
||||
{
|
||||
|
@ -3,23 +3,17 @@
|
||||
namespace DesignPatterns\Behavioral\Command;
|
||||
|
||||
/**
|
||||
* Receiver is specific service with its own contract and can be only concrete.
|
||||
* Receiver is a specific service with its own contract and can be only concrete.
|
||||
*/
|
||||
class Receiver
|
||||
{
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $enableDate = false;
|
||||
private bool $enableDate = false;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
private $output = [];
|
||||
private array $output = [];
|
||||
|
||||
/**
|
||||
* @param string $str
|
||||
*/
|
||||
public function write(string $str)
|
||||
{
|
||||
if ($this->enableDate) {
|
||||
|
@ -4,15 +4,8 @@ namespace DesignPatterns\Behavioral\Iterator;
|
||||
|
||||
class Book
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $author;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $title;
|
||||
private string $author;
|
||||
private string $title;
|
||||
|
||||
public function __construct(string $title, string $author)
|
||||
{
|
||||
|
@ -2,17 +2,16 @@
|
||||
|
||||
namespace DesignPatterns\Behavioral\Iterator;
|
||||
|
||||
class BookList implements \Countable, \Iterator
|
||||
use Countable;
|
||||
use Iterator;
|
||||
|
||||
class BookList implements Countable, Iterator
|
||||
{
|
||||
/**
|
||||
* @var Book[]
|
||||
*/
|
||||
private $books = [];
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $currentIndex = 0;
|
||||
private array $books = [];
|
||||
private int $currentIndex = 0;
|
||||
|
||||
public function addBook(Book $book)
|
||||
{
|
||||
|
@ -4,14 +4,8 @@ namespace DesignPatterns\Behavioral\Mediator;
|
||||
|
||||
abstract class Colleague
|
||||
{
|
||||
/**
|
||||
* @var Mediator
|
||||
*/
|
||||
protected $mediator;
|
||||
protected Mediator $mediator;
|
||||
|
||||
/**
|
||||
* @param Mediator $mediator
|
||||
*/
|
||||
public function setMediator(Mediator $mediator)
|
||||
{
|
||||
$this->mediator = $mediator;
|
||||
|
@ -11,7 +11,7 @@ class MediatorTest extends TestCase
|
||||
{
|
||||
public function testOutputHelloWorld()
|
||||
{
|
||||
$mediator = new UserRepositoryUiMediator(new UserRepository(), new UI());
|
||||
$mediator = new UserRepositoryUiMediator(new UserRepository(), new Ui());
|
||||
|
||||
$this->expectOutputString('User: Dominik');
|
||||
$mediator->printInfoAbout('Dominik');
|
||||
|
@ -4,15 +4,8 @@ namespace DesignPatterns\Behavioral\Mediator;
|
||||
|
||||
class UserRepositoryUiMediator implements Mediator
|
||||
{
|
||||
/**
|
||||
* @var UserRepository
|
||||
*/
|
||||
private $userRepository;
|
||||
|
||||
/**
|
||||
* @var Ui
|
||||
*/
|
||||
private $ui;
|
||||
private UserRepository $userRepository;
|
||||
private Ui $ui;
|
||||
|
||||
public function __construct(UserRepository $userRepository, Ui $ui)
|
||||
{
|
||||
|
@ -4,23 +4,14 @@ namespace DesignPatterns\Behavioral\Memento;
|
||||
|
||||
class Memento
|
||||
{
|
||||
/**
|
||||
* @var State
|
||||
*/
|
||||
private $state;
|
||||
private State $state;
|
||||
|
||||
/**
|
||||
* @param State $stateToSave
|
||||
*/
|
||||
public function __construct(State $stateToSave)
|
||||
{
|
||||
$this->state = $stateToSave;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return State
|
||||
*/
|
||||
public function getState()
|
||||
public function getState(): State
|
||||
{
|
||||
return $this->state;
|
||||
}
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
namespace DesignPatterns\Behavioral\Memento;
|
||||
|
||||
use InvalidArgumentException;
|
||||
|
||||
class State
|
||||
{
|
||||
const STATE_CREATED = 'created';
|
||||
@ -9,24 +11,18 @@ class State
|
||||
const STATE_ASSIGNED = 'assigned';
|
||||
const STATE_CLOSED = 'closed';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $state;
|
||||
private string $state;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
private static $validStates = [
|
||||
private static array $validStates = [
|
||||
self::STATE_CREATED,
|
||||
self::STATE_OPENED,
|
||||
self::STATE_ASSIGNED,
|
||||
self::STATE_CLOSED,
|
||||
];
|
||||
|
||||
/**
|
||||
* @param string $state
|
||||
*/
|
||||
public function __construct(string $state)
|
||||
{
|
||||
self::ensureIsValidState($state);
|
||||
@ -37,7 +33,7 @@ class State
|
||||
private static function ensureIsValidState(string $state)
|
||||
{
|
||||
if (!in_array($state, self::$validStates)) {
|
||||
throw new \InvalidArgumentException('Invalid state given');
|
||||
throw new InvalidArgumentException('Invalid state given');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,10 +7,7 @@ namespace DesignPatterns\Behavioral\Memento;
|
||||
*/
|
||||
class Ticket
|
||||
{
|
||||
/**
|
||||
* @var State
|
||||
*/
|
||||
private $currentState;
|
||||
private State $currentState;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
|
@ -4,14 +4,8 @@ namespace DesignPatterns\Behavioral\NullObject;
|
||||
|
||||
class Service
|
||||
{
|
||||
/**
|
||||
* @var Logger
|
||||
*/
|
||||
private $logger;
|
||||
private Logger $logger;
|
||||
|
||||
/**
|
||||
* @param Logger $logger
|
||||
*/
|
||||
public function __construct(Logger $logger)
|
||||
{
|
||||
$this->logger = $logger;
|
||||
|
@ -2,33 +2,30 @@
|
||||
|
||||
namespace DesignPatterns\Behavioral\Observer;
|
||||
|
||||
use SplSubject;
|
||||
use SplObjectStorage;
|
||||
use SplObserver;
|
||||
|
||||
/**
|
||||
* User implements the observed object (called Subject), it maintains a list of observers and sends notifications to
|
||||
* them in case changes are made on the User object
|
||||
*/
|
||||
class User implements \SplSubject
|
||||
class User implements SplSubject
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $email;
|
||||
|
||||
/**
|
||||
* @var \SplObjectStorage
|
||||
*/
|
||||
private $observers;
|
||||
private string $email;
|
||||
private SplObjectStorage $observers;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->observers = new \SplObjectStorage();
|
||||
$this->observers = new SplObjectStorage();
|
||||
}
|
||||
|
||||
public function attach(\SplObserver $observer)
|
||||
public function attach(SplObserver $observer)
|
||||
{
|
||||
$this->observers->attach($observer);
|
||||
}
|
||||
|
||||
public function detach(\SplObserver $observer)
|
||||
public function detach(SplObserver $observer)
|
||||
{
|
||||
$this->observers->detach($observer);
|
||||
}
|
||||
@ -41,7 +38,7 @@ class User implements \SplSubject
|
||||
|
||||
public function notify()
|
||||
{
|
||||
/** @var \SplObserver $observer */
|
||||
/** @var SplObserver $observer */
|
||||
foreach ($this->observers as $observer) {
|
||||
$observer->update($this);
|
||||
}
|
||||
|
@ -2,19 +2,18 @@
|
||||
|
||||
namespace DesignPatterns\Behavioral\Observer;
|
||||
|
||||
use SplObserver;
|
||||
use SplSubject;
|
||||
|
||||
class UserObserver implements \SplObserver
|
||||
class UserObserver implements SplObserver
|
||||
{
|
||||
/**
|
||||
* @var SplSubject[]
|
||||
*/
|
||||
private $changedUsers = [];
|
||||
private array $changedUsers = [];
|
||||
|
||||
/**
|
||||
* It is called by the Subject, usually by SplSubject::notify()
|
||||
*
|
||||
* @param SplSubject $subject
|
||||
*/
|
||||
public function update(SplSubject $subject)
|
||||
{
|
||||
|
@ -7,7 +7,7 @@ class AndSpecification implements Specification
|
||||
/**
|
||||
* @var Specification[]
|
||||
*/
|
||||
private $specifications;
|
||||
private array $specifications;
|
||||
|
||||
/**
|
||||
* @param Specification[] $specifications
|
||||
|
@ -4,10 +4,7 @@ namespace DesignPatterns\Behavioral\Specification;
|
||||
|
||||
class Item
|
||||
{
|
||||
/**
|
||||
* @var float
|
||||
*/
|
||||
private $price;
|
||||
private float $price;
|
||||
|
||||
public function __construct(float $price)
|
||||
{
|
||||
|
@ -4,10 +4,7 @@ namespace DesignPatterns\Behavioral\Specification;
|
||||
|
||||
class NotSpecification implements Specification
|
||||
{
|
||||
/**
|
||||
* @var Specification
|
||||
*/
|
||||
private $specification;
|
||||
private Specification $specification;
|
||||
|
||||
public function __construct(Specification $specification)
|
||||
{
|
||||
|
@ -7,7 +7,7 @@ class OrSpecification implements Specification
|
||||
/**
|
||||
* @var Specification[]
|
||||
*/
|
||||
private $specifications;
|
||||
private array $specifications;
|
||||
|
||||
/**
|
||||
* @param Specification[] $specifications
|
||||
@ -27,6 +27,7 @@ class OrSpecification implements Specification
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -4,21 +4,10 @@ namespace DesignPatterns\Behavioral\Specification;
|
||||
|
||||
class PriceSpecification implements Specification
|
||||
{
|
||||
/**
|
||||
* @var float|null
|
||||
*/
|
||||
private $maxPrice;
|
||||
private ?float $maxPrice;
|
||||
private ?float $minPrice;
|
||||
|
||||
/**
|
||||
* @var float|null
|
||||
*/
|
||||
private $minPrice;
|
||||
|
||||
/**
|
||||
* @param float $minPrice
|
||||
* @param float $maxPrice
|
||||
*/
|
||||
public function __construct($minPrice, $maxPrice)
|
||||
public function __construct(?float $minPrice, ?float $maxPrice)
|
||||
{
|
||||
$this->minPrice = $minPrice;
|
||||
$this->maxPrice = $maxPrice;
|
||||
|
@ -4,10 +4,7 @@ namespace DesignPatterns\Behavioral\State;
|
||||
|
||||
class OrderContext
|
||||
{
|
||||
/**
|
||||
* @var State
|
||||
*/
|
||||
private $state;
|
||||
private State $state;
|
||||
|
||||
public static function create(): OrderContext
|
||||
{
|
||||
|
@ -4,17 +4,14 @@ namespace DesignPatterns\Behavioral\Strategy;
|
||||
|
||||
class Context
|
||||
{
|
||||
/**
|
||||
* @var Comparator
|
||||
*/
|
||||
private $comparator;
|
||||
private Comparator $comparator;
|
||||
|
||||
public function __construct(Comparator $comparator)
|
||||
{
|
||||
$this->comparator = $comparator;
|
||||
}
|
||||
|
||||
public function executeStrategy(array $elements) : array
|
||||
public function executeStrategy(array $elements): array
|
||||
{
|
||||
uasort($elements, [$this->comparator, 'compare']);
|
||||
|
||||
|
@ -2,18 +2,14 @@
|
||||
|
||||
namespace DesignPatterns\Behavioral\Strategy;
|
||||
|
||||
use DateTime;
|
||||
|
||||
class DateComparator implements Comparator
|
||||
{
|
||||
/**
|
||||
* @param mixed $a
|
||||
* @param mixed $b
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function compare($a, $b): int
|
||||
{
|
||||
$aDate = new \DateTime($a['date']);
|
||||
$bDate = new \DateTime($b['date']);
|
||||
$aDate = new DateTime($a['date']);
|
||||
$bDate = new DateTime($b['date']);
|
||||
|
||||
return $aDate <=> $bDate;
|
||||
}
|
||||
|
@ -4,12 +4,6 @@ namespace DesignPatterns\Behavioral\Strategy;
|
||||
|
||||
class IdComparator implements Comparator
|
||||
{
|
||||
/**
|
||||
* @param mixed $a
|
||||
* @param mixed $b
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function compare($a, $b): int
|
||||
{
|
||||
return $a['id'] <=> $b['id'];
|
||||
|
@ -9,7 +9,7 @@ class CityJourney extends Journey
|
||||
return "Eat, drink, take photos and sleep";
|
||||
}
|
||||
|
||||
protected function buyGift(): string
|
||||
protected function buyGift(): ?string
|
||||
{
|
||||
return "Buy a gift";
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ abstract class Journey
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
private $thingsToDo = [];
|
||||
private array $thingsToDo = [];
|
||||
|
||||
/**
|
||||
* This is the public service provided by this class and its subclasses.
|
||||
@ -37,10 +37,8 @@ abstract class Journey
|
||||
/**
|
||||
* This method is also part of the algorithm but it is optional.
|
||||
* You can override it only if you need to
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
protected function buyGift()
|
||||
protected function buyGift(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
@ -2,14 +2,15 @@
|
||||
|
||||
namespace DesignPatterns\Behavioral\TemplateMethod\Tests;
|
||||
|
||||
use DesignPatterns\Behavioral\TemplateMethod;
|
||||
use DesignPatterns\Behavioral\TemplateMethod\BeachJourney;
|
||||
use DesignPatterns\Behavioral\TemplateMethod\CityJourney;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class JourneyTest extends TestCase
|
||||
{
|
||||
public function testCanGetOnVacationOnTheBeach()
|
||||
{
|
||||
$beachJourney = new TemplateMethod\BeachJourney();
|
||||
$beachJourney = new BeachJourney();
|
||||
$beachJourney->takeATrip();
|
||||
|
||||
$this->assertSame(
|
||||
@ -20,7 +21,7 @@ class JourneyTest extends TestCase
|
||||
|
||||
public function testCanGetOnAJourneyToACity()
|
||||
{
|
||||
$cityJourney = new TemplateMethod\CityJourney();
|
||||
$cityJourney = new CityJourney();
|
||||
$cityJourney->takeATrip();
|
||||
|
||||
$this->assertSame(
|
||||
|
@ -4,10 +4,7 @@ namespace DesignPatterns\Behavioral\Visitor;
|
||||
|
||||
class Group implements Role
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $name;
|
||||
private string $name;
|
||||
|
||||
public function __construct(string $name)
|
||||
{
|
||||
|
@ -7,7 +7,7 @@ class RecordingVisitor implements RoleVisitor
|
||||
/**
|
||||
* @var Role[]
|
||||
*/
|
||||
private $visited = [];
|
||||
private array $visited = [];
|
||||
|
||||
public function visitGroup(Group $role)
|
||||
{
|
||||
|
@ -2,35 +2,34 @@
|
||||
|
||||
namespace DesignPatterns\Tests\Visitor\Tests;
|
||||
|
||||
use DesignPatterns\Behavioral\Visitor\RecordingVisitor;
|
||||
use DesignPatterns\Behavioral\Visitor\User;
|
||||
use DesignPatterns\Behavioral\Visitor\Group;
|
||||
use DesignPatterns\Behavioral\Visitor\Role;
|
||||
use DesignPatterns\Behavioral\Visitor;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class VisitorTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var Visitor\RecordingVisitor
|
||||
*/
|
||||
private $visitor;
|
||||
private RecordingVisitor $visitor;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->visitor = new Visitor\RecordingVisitor();
|
||||
$this->visitor = new RecordingVisitor();
|
||||
}
|
||||
|
||||
public function provideRoles()
|
||||
{
|
||||
return [
|
||||
[new Visitor\User('Dominik')],
|
||||
[new Visitor\Group('Administrators')],
|
||||
[new User('Dominik')],
|
||||
[new Group('Administrators')],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideRoles
|
||||
*
|
||||
* @param Visitor\Role $role
|
||||
*/
|
||||
public function testVisitSomeRole(Visitor\Role $role)
|
||||
public function testVisitSomeRole(Role $role)
|
||||
{
|
||||
$role->accept($this->visitor);
|
||||
$this->assertSame($role, $this->visitor->getVisited()[0]);
|
||||
|
@ -4,10 +4,7 @@ namespace DesignPatterns\Behavioral\Visitor;
|
||||
|
||||
class User implements Role
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $name;
|
||||
private string $name;
|
||||
|
||||
public function __construct(string $name)
|
||||
{
|
||||
|
@ -2,38 +2,39 @@
|
||||
|
||||
namespace DesignPatterns\Creational\Builder;
|
||||
|
||||
use DesignPatterns\Creational\Builder\Parts\Door;
|
||||
use DesignPatterns\Creational\Builder\Parts\Engine;
|
||||
use DesignPatterns\Creational\Builder\Parts\Wheel;
|
||||
use DesignPatterns\Creational\Builder\Parts\Car;
|
||||
use DesignPatterns\Creational\Builder\Parts\Vehicle;
|
||||
|
||||
class CarBuilder implements Builder
|
||||
{
|
||||
/**
|
||||
* @var Parts\Car
|
||||
*/
|
||||
private $car;
|
||||
private Car $car;
|
||||
|
||||
public function addDoors()
|
||||
{
|
||||
$this->car->setPart('rightDoor', new Parts\Door());
|
||||
$this->car->setPart('leftDoor', new Parts\Door());
|
||||
$this->car->setPart('trunkLid', new Parts\Door());
|
||||
$this->car->setPart('rightDoor', new Door());
|
||||
$this->car->setPart('leftDoor', new Door());
|
||||
$this->car->setPart('trunkLid', new Door());
|
||||
}
|
||||
|
||||
public function addEngine()
|
||||
{
|
||||
$this->car->setPart('engine', new Parts\Engine());
|
||||
$this->car->setPart('engine', new Engine());
|
||||
}
|
||||
|
||||
public function addWheel()
|
||||
{
|
||||
$this->car->setPart('wheelLF', new Parts\Wheel());
|
||||
$this->car->setPart('wheelRF', new Parts\Wheel());
|
||||
$this->car->setPart('wheelLR', new Parts\Wheel());
|
||||
$this->car->setPart('wheelRR', new Parts\Wheel());
|
||||
$this->car->setPart('wheelLF', new Wheel());
|
||||
$this->car->setPart('wheelRF', new Wheel());
|
||||
$this->car->setPart('wheelLR', new Wheel());
|
||||
$this->car->setPart('wheelRR', new Wheel());
|
||||
}
|
||||
|
||||
public function createVehicle()
|
||||
{
|
||||
$this->car = new Parts\Car();
|
||||
$this->car = new Car();
|
||||
}
|
||||
|
||||
public function getVehicle(): Vehicle
|
||||
|
@ -7,13 +7,9 @@ abstract class Vehicle
|
||||
/**
|
||||
* @var object[]
|
||||
*/
|
||||
private $data = [];
|
||||
private array $data = [];
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param object $value
|
||||
*/
|
||||
public function setPart($key, $value)
|
||||
public function setPart(string $key, object $value)
|
||||
{
|
||||
$this->data[$key] = $value;
|
||||
}
|
||||
|
@ -2,39 +2,40 @@
|
||||
|
||||
namespace DesignPatterns\Creational\Builder;
|
||||
|
||||
use DesignPatterns\Creational\Builder\Parts\Door;
|
||||
use DesignPatterns\Creational\Builder\Parts\Engine;
|
||||
use DesignPatterns\Creational\Builder\Parts\Wheel;
|
||||
use DesignPatterns\Creational\Builder\Parts\Truck;
|
||||
use DesignPatterns\Creational\Builder\Parts\Vehicle;
|
||||
|
||||
class TruckBuilder implements Builder
|
||||
{
|
||||
/**
|
||||
* @var Parts\Truck
|
||||
*/
|
||||
private $truck;
|
||||
private Truck $truck;
|
||||
|
||||
public function addDoors()
|
||||
{
|
||||
$this->truck->setPart('rightDoor', new Parts\Door());
|
||||
$this->truck->setPart('leftDoor', new Parts\Door());
|
||||
$this->truck->setPart('rightDoor', new Door());
|
||||
$this->truck->setPart('leftDoor', new Door());
|
||||
}
|
||||
|
||||
public function addEngine()
|
||||
{
|
||||
$this->truck->setPart('truckEngine', new Parts\Engine());
|
||||
$this->truck->setPart('truckEngine', new Engine());
|
||||
}
|
||||
|
||||
public function addWheel()
|
||||
{
|
||||
$this->truck->setPart('wheel1', new Parts\Wheel());
|
||||
$this->truck->setPart('wheel2', new Parts\Wheel());
|
||||
$this->truck->setPart('wheel3', new Parts\Wheel());
|
||||
$this->truck->setPart('wheel4', new Parts\Wheel());
|
||||
$this->truck->setPart('wheel5', new Parts\Wheel());
|
||||
$this->truck->setPart('wheel6', new Parts\Wheel());
|
||||
$this->truck->setPart('wheel1', new Wheel());
|
||||
$this->truck->setPart('wheel2', new Wheel());
|
||||
$this->truck->setPart('wheel3', new Wheel());
|
||||
$this->truck->setPart('wheel4', new Wheel());
|
||||
$this->truck->setPart('wheel5', new Wheel());
|
||||
$this->truck->setPart('wheel6', new Wheel());
|
||||
}
|
||||
|
||||
public function createVehicle()
|
||||
{
|
||||
$this->truck = new Parts\Truck();
|
||||
$this->truck = new Truck();
|
||||
}
|
||||
|
||||
public function getVehicle(): Vehicle
|
||||
|
@ -4,10 +4,7 @@ namespace DesignPatterns\Creational\FactoryMethod;
|
||||
|
||||
class FileLogger implements Logger
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $filePath;
|
||||
private string $filePath;
|
||||
|
||||
public function __construct(string $filePath)
|
||||
{
|
||||
|
@ -4,10 +4,7 @@ namespace DesignPatterns\Creational\FactoryMethod;
|
||||
|
||||
class FileLoggerFactory implements LoggerFactory
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $filePath;
|
||||
private string $filePath;
|
||||
|
||||
public function __construct(string $filePath)
|
||||
{
|
||||
|
@ -10,7 +10,7 @@ final class Multiton
|
||||
/**
|
||||
* @var Multiton[]
|
||||
*/
|
||||
private static $instances = [];
|
||||
private static array $instances = [];
|
||||
|
||||
/**
|
||||
* this is private to prevent from creating arbitrary instances
|
||||
|
@ -2,16 +2,15 @@
|
||||
|
||||
namespace DesignPatterns\Creational\Pool;
|
||||
|
||||
use DateTime;
|
||||
|
||||
class StringReverseWorker
|
||||
{
|
||||
/**
|
||||
* @var \DateTime
|
||||
*/
|
||||
private $createdAt;
|
||||
private DateTime $createdAt;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->createdAt = new \DateTime();
|
||||
$this->createdAt = new DateTime();
|
||||
}
|
||||
|
||||
public function run(string $text)
|
||||
|
@ -2,17 +2,19 @@
|
||||
|
||||
namespace DesignPatterns\Creational\Pool;
|
||||
|
||||
class WorkerPool implements \Countable
|
||||
use Countable;
|
||||
|
||||
class WorkerPool implements Countable
|
||||
{
|
||||
/**
|
||||
* @var StringReverseWorker[]
|
||||
*/
|
||||
private $occupiedWorkers = [];
|
||||
private array $occupiedWorkers = [];
|
||||
|
||||
/**
|
||||
* @var StringReverseWorker[]
|
||||
*/
|
||||
private $freeWorkers = [];
|
||||
private array $freeWorkers = [];
|
||||
|
||||
public function get(): StringReverseWorker
|
||||
{
|
||||
|
@ -4,10 +4,7 @@ namespace DesignPatterns\Creational\Prototype;
|
||||
|
||||
class BarBookPrototype extends BookPrototype
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $category = 'Bar';
|
||||
protected string $category = 'Bar';
|
||||
|
||||
public function __clone()
|
||||
{
|
||||
|
@ -4,15 +4,8 @@ namespace DesignPatterns\Creational\Prototype;
|
||||
|
||||
abstract class BookPrototype
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $title;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $category;
|
||||
protected string $title;
|
||||
protected string $category;
|
||||
|
||||
abstract public function __clone();
|
||||
|
||||
@ -21,7 +14,7 @@ abstract class BookPrototype
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
public function setTitle($title)
|
||||
public function setTitle(string $title)
|
||||
{
|
||||
$this->title = $title;
|
||||
}
|
||||
|
@ -4,10 +4,7 @@ namespace DesignPatterns\Creational\Prototype;
|
||||
|
||||
class FooBookPrototype extends BookPrototype
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $category = 'Foo';
|
||||
protected string $category = 'Foo';
|
||||
|
||||
public function __clone()
|
||||
{
|
||||
|
@ -4,10 +4,7 @@ namespace DesignPatterns\Creational\Singleton;
|
||||
|
||||
final class Singleton
|
||||
{
|
||||
/**
|
||||
* @var Singleton
|
||||
*/
|
||||
private static $instance;
|
||||
private static ?Singleton $instance = null;
|
||||
|
||||
/**
|
||||
* gets the instance via lazy initialization (created on first usage)
|
||||
|
@ -2,17 +2,14 @@
|
||||
|
||||
namespace DesignPatterns\Creational\StaticFactory;
|
||||
|
||||
use InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* Note1: Remember, static means global state which is evil because it can't be mocked for tests
|
||||
* Note2: Cannot be subclassed or mock-upped or have multiple different instances.
|
||||
*/
|
||||
final class StaticFactory
|
||||
{
|
||||
/**
|
||||
* @param string $type
|
||||
*
|
||||
* @return Formatter
|
||||
*/
|
||||
public static function factory(string $type): Formatter
|
||||
{
|
||||
if ($type == 'number') {
|
||||
@ -21,6 +18,6 @@ final class StaticFactory
|
||||
return new FormatString();
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException('Unknown format given');
|
||||
throw new InvalidArgumentException('Unknown format given');
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace DesignPatterns\Creational\StaticFactory\Tests;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use DesignPatterns\Creational\StaticFactory\FormatNumber;
|
||||
use DesignPatterns\Creational\StaticFactory\FormatString;
|
||||
use DesignPatterns\Creational\StaticFactory\StaticFactory;
|
||||
@ -21,7 +22,7 @@ class StaticFactoryTest extends TestCase
|
||||
|
||||
public function testException()
|
||||
{
|
||||
$this->expectException(\InvalidArgumentException::class);
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
|
||||
StaticFactory::factory('object');
|
||||
}
|
||||
|
@ -2,21 +2,16 @@
|
||||
|
||||
namespace DesignPatterns\More\EAV;
|
||||
|
||||
use SplObjectStorage;
|
||||
|
||||
class Attribute
|
||||
{
|
||||
/**
|
||||
* @var \SplObjectStorage
|
||||
*/
|
||||
private $values;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $name;
|
||||
private SplObjectStorage $values;
|
||||
private string $name;
|
||||
|
||||
public function __construct(string $name)
|
||||
{
|
||||
$this->values = new \SplObjectStorage();
|
||||
$this->values = new SplObjectStorage();
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
@ -25,10 +20,7 @@ class Attribute
|
||||
$this->values->attach($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \SplObjectStorage
|
||||
*/
|
||||
public function getValues(): \SplObjectStorage
|
||||
public function getValues(): SplObjectStorage
|
||||
{
|
||||
return $this->values;
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ class Entity
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $name;
|
||||
private string $name;
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
@ -22,6 +22,7 @@ class Entity
|
||||
*/
|
||||
public function __construct(string $name, $values)
|
||||
{
|
||||
/** @var SplObjectStorage<Value,Value> values */
|
||||
$this->values = new SplObjectStorage();
|
||||
$this->name = $name;
|
||||
|
||||
|
@ -4,15 +4,8 @@ namespace DesignPatterns\More\EAV;
|
||||
|
||||
class Value
|
||||
{
|
||||
/**
|
||||
* @var Attribute
|
||||
*/
|
||||
private $attribute;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $name;
|
||||
private Attribute $attribute;
|
||||
private string $name;
|
||||
|
||||
public function __construct(Attribute $attribute, string $name)
|
||||
{
|
||||
|
@ -4,25 +4,10 @@ namespace DesignPatterns\More\Repository\Domain;
|
||||
|
||||
class Post
|
||||
{
|
||||
/**
|
||||
* @var PostId
|
||||
*/
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* @var PostStatus
|
||||
*/
|
||||
private $status;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $title;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $text;
|
||||
private PostId $id;
|
||||
private PostStatus $status;
|
||||
private string $title;
|
||||
private string $text;
|
||||
|
||||
public static function draft(PostId $id, string $title, string $text): Post
|
||||
{
|
||||
@ -44,12 +29,6 @@ class Post
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PostId $id
|
||||
* @param PostStatus $status
|
||||
* @param string $title
|
||||
* @param string $text
|
||||
*/
|
||||
private function __construct(PostId $id, PostStatus $status, string $title, string $text)
|
||||
{
|
||||
$this->id = $id;
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
namespace DesignPatterns\More\Repository\Domain;
|
||||
|
||||
use InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* This is a perfect example of a value object that is identifiable by it's value alone and
|
||||
* is guaranteed to be valid each time an instance is created. Another important property of value objects
|
||||
@ -11,12 +13,9 @@ namespace DesignPatterns\More\Repository\Domain;
|
||||
*/
|
||||
class PostId
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $id;
|
||||
private int $id;
|
||||
|
||||
public static function fromInt(int $id)
|
||||
public static function fromInt(int $id): PostId
|
||||
{
|
||||
self::ensureIsValid($id);
|
||||
|
||||
@ -36,7 +35,7 @@ class PostId
|
||||
private static function ensureIsValid(int $id)
|
||||
{
|
||||
if ($id <= 0) {
|
||||
throw new \InvalidArgumentException('Invalid PostId given');
|
||||
throw new InvalidArgumentException('Invalid PostId given');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
namespace DesignPatterns\More\Repository\Domain;
|
||||
|
||||
use InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* Like PostId, this is a value object which holds the value of the current status of a Post. It can be constructed
|
||||
* either from a string or int and is able to validate itself. An instance can then be converted back to int or string.
|
||||
@ -14,20 +16,13 @@ class PostStatus
|
||||
const STATE_DRAFT = 'draft';
|
||||
const STATE_PUBLISHED = 'published';
|
||||
|
||||
private static $validStates = [
|
||||
private static array $validStates = [
|
||||
self::STATE_DRAFT_ID => self::STATE_DRAFT,
|
||||
self::STATE_PUBLISHED_ID => self::STATE_PUBLISHED,
|
||||
];
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $name;
|
||||
private int $id;
|
||||
private string $name;
|
||||
|
||||
public static function fromInt(int $statusId)
|
||||
{
|
||||
@ -39,8 +34,13 @@ class PostStatus
|
||||
public static function fromString(string $status)
|
||||
{
|
||||
self::ensureIsValidName($status);
|
||||
$state = array_search($status, self::$validStates);
|
||||
|
||||
return new self(array_search($status, self::$validStates), $status);
|
||||
if ($state === false) {
|
||||
throw new InvalidArgumentException('Invalid state given!');
|
||||
}
|
||||
|
||||
return new self($state, $status);
|
||||
}
|
||||
|
||||
private function __construct(int $id, string $name)
|
||||
@ -66,7 +66,7 @@ class PostStatus
|
||||
private static function ensureIsValidId(int $status)
|
||||
{
|
||||
if (!in_array($status, array_keys(self::$validStates), true)) {
|
||||
throw new \InvalidArgumentException('Invalid status id given');
|
||||
throw new InvalidArgumentException('Invalid status id given');
|
||||
}
|
||||
}
|
||||
|
||||
@ -74,7 +74,7 @@ class PostStatus
|
||||
private static function ensureIsValidName(string $status)
|
||||
{
|
||||
if (!in_array($status, self::$validStates, true)) {
|
||||
throw new \InvalidArgumentException('Invalid status name given');
|
||||
throw new InvalidArgumentException('Invalid status name given');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,17 +2,12 @@
|
||||
|
||||
namespace DesignPatterns\More\Repository;
|
||||
|
||||
use OutOfBoundsException;
|
||||
|
||||
class InMemoryPersistence implements Persistence
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $data = [];
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $lastId = 0;
|
||||
private array $data = [];
|
||||
private int $lastId = 0;
|
||||
|
||||
public function generateId(): int
|
||||
{
|
||||
@ -29,7 +24,7 @@ class InMemoryPersistence implements Persistence
|
||||
public function retrieve(int $id): array
|
||||
{
|
||||
if (!isset($this->data[$id])) {
|
||||
throw new \OutOfBoundsException(sprintf('No data found for ID %d', $id));
|
||||
throw new OutOfBoundsException(sprintf('No data found for ID %d', $id));
|
||||
}
|
||||
|
||||
return $this->data[$id];
|
||||
@ -38,7 +33,7 @@ class InMemoryPersistence implements Persistence
|
||||
public function delete(int $id)
|
||||
{
|
||||
if (!isset($this->data[$id])) {
|
||||
throw new \OutOfBoundsException(sprintf('No data found for ID %d', $id));
|
||||
throw new OutOfBoundsException(sprintf('No data found for ID %d', $id));
|
||||
}
|
||||
|
||||
unset($this->data[$id]);
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace DesignPatterns\More\Repository;
|
||||
|
||||
use OutOfBoundsException;
|
||||
use DesignPatterns\More\Repository\Domain\Post;
|
||||
use DesignPatterns\More\Repository\Domain\PostId;
|
||||
|
||||
@ -16,10 +17,7 @@ use DesignPatterns\More\Repository\Domain\PostId;
|
||||
*/
|
||||
class PostRepository
|
||||
{
|
||||
/**
|
||||
* @var Persistence
|
||||
*/
|
||||
private $persistence;
|
||||
private Persistence $persistence;
|
||||
|
||||
public function __construct(Persistence $persistence)
|
||||
{
|
||||
@ -35,8 +33,8 @@ class PostRepository
|
||||
{
|
||||
try {
|
||||
$arrayData = $this->persistence->retrieve($id->toInt());
|
||||
} catch (\OutOfBoundsException $e) {
|
||||
throw new \OutOfBoundsException(sprintf('Post with id %d does not exist', $id->toInt()), 0, $e);
|
||||
} catch (OutOfBoundsException $e) {
|
||||
throw new OutOfBoundsException(sprintf('Post with id %d does not exist', $id->toInt()), 0, $e);
|
||||
}
|
||||
|
||||
return Post::fromState($arrayData);
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace DesignPatterns\More\Repository\Tests;
|
||||
|
||||
use OutOfBoundsException;
|
||||
use DesignPatterns\More\Repository\Domain\PostId;
|
||||
use DesignPatterns\More\Repository\Domain\PostStatus;
|
||||
use DesignPatterns\More\Repository\InMemoryPersistence;
|
||||
@ -11,10 +12,7 @@ use PHPUnit\Framework\TestCase;
|
||||
|
||||
class PostRepositoryTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var PostRepository
|
||||
*/
|
||||
private $repository;
|
||||
private PostRepository $repository;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
@ -28,7 +26,7 @@ class PostRepositoryTest extends TestCase
|
||||
|
||||
public function testThrowsExceptionWhenTryingToFindPostWhichDoesNotExist()
|
||||
{
|
||||
$this->expectException(\OutOfBoundsException::class);
|
||||
$this->expectException(OutOfBoundsException::class);
|
||||
$this->expectExceptionMessage('Post with id 42 does not exist');
|
||||
|
||||
$this->repository->findById(PostId::fromInt(42));
|
||||
|
@ -2,17 +2,20 @@
|
||||
|
||||
namespace DesignPatterns\More\ServiceLocator;
|
||||
|
||||
use OutOfRangeException;
|
||||
use InvalidArgumentException;
|
||||
|
||||
class ServiceLocator
|
||||
{
|
||||
/**
|
||||
* @var string[][]
|
||||
*/
|
||||
private $services = [];
|
||||
private array $services = [];
|
||||
|
||||
/**
|
||||
* @var Service[]
|
||||
*/
|
||||
private $instantiated = [];
|
||||
private array $instantiated = [];
|
||||
|
||||
public function addInstance(string $class, Service $service)
|
||||
{
|
||||
@ -51,11 +54,11 @@ class ServiceLocator
|
||||
$object = new $class($args[0], $args[1], $args[2]);
|
||||
break;
|
||||
default:
|
||||
throw new \OutOfRangeException('Too many arguments given');
|
||||
throw new OutOfRangeException('Too many arguments given');
|
||||
}
|
||||
|
||||
if (!$object instanceof Service) {
|
||||
throw new \InvalidArgumentException('Could not register service: is no instance of Service');
|
||||
throw new InvalidArgumentException('Could not register service: is no instance of Service');
|
||||
}
|
||||
|
||||
$this->instantiated[$class] = $object;
|
||||
|
@ -8,10 +8,7 @@ use PHPUnit\Framework\TestCase;
|
||||
|
||||
class ServiceLocatorTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var ServiceLocator
|
||||
*/
|
||||
private $serviceLocator;
|
||||
private ServiceLocator $serviceLocator;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
|
@ -8,14 +8,8 @@ namespace DesignPatterns\Structural\Adapter;
|
||||
*/
|
||||
class EBookAdapter implements Book
|
||||
{
|
||||
/**
|
||||
* @var EBook
|
||||
*/
|
||||
protected $eBook;
|
||||
protected EBook $eBook;
|
||||
|
||||
/**
|
||||
* @param EBook $eBook
|
||||
*/
|
||||
public function __construct(EBook $eBook)
|
||||
{
|
||||
$this->eBook = $eBook;
|
||||
@ -37,8 +31,6 @@ class EBookAdapter implements Book
|
||||
/**
|
||||
* notice the adapted behavior here: EBook::getPage() will return two integers, but Book
|
||||
* supports only a current page getter, so we adapt the behavior here
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getPage(): int
|
||||
{
|
||||
|
@ -8,15 +8,8 @@ namespace DesignPatterns\Structural\Adapter;
|
||||
*/
|
||||
class Kindle implements EBook
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $page = 1;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $totalPages = 100;
|
||||
private int $page = 1;
|
||||
private int $totalPages = 100;
|
||||
|
||||
public function pressNext()
|
||||
{
|
||||
|
@ -4,10 +4,7 @@ namespace DesignPatterns\Structural\Adapter;
|
||||
|
||||
class PaperBook implements Book
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $page;
|
||||
private int $page;
|
||||
|
||||
public function open()
|
||||
{
|
||||
|
@ -4,22 +4,13 @@ namespace DesignPatterns\Structural\Bridge;
|
||||
|
||||
abstract class Service
|
||||
{
|
||||
/**
|
||||
* @var Formatter
|
||||
*/
|
||||
protected $implementation;
|
||||
protected Formatter $implementation;
|
||||
|
||||
/**
|
||||
* @param Formatter $printer
|
||||
*/
|
||||
public function __construct(Formatter $printer)
|
||||
{
|
||||
$this->implementation = $printer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Formatter $printer
|
||||
*/
|
||||
public function setImplementation(Formatter $printer)
|
||||
{
|
||||
$this->implementation = $printer;
|
||||
|
@ -11,15 +11,13 @@ class Form implements Renderable
|
||||
/**
|
||||
* @var Renderable[]
|
||||
*/
|
||||
private $elements;
|
||||
private array $elements;
|
||||
|
||||
/**
|
||||
* runs through all elements and calls render() on them, then returns the complete representation
|
||||
* of the form.
|
||||
*
|
||||
* from the outside, one will not see this and the form will act like a single object instance
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function render(): string
|
||||
{
|
||||
@ -34,9 +32,6 @@ class Form implements Renderable
|
||||
return $formCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Renderable $element
|
||||
*/
|
||||
public function addElement(Renderable $element)
|
||||
{
|
||||
$this->elements[] = $element;
|
||||
|
@ -2,19 +2,21 @@
|
||||
|
||||
namespace DesignPatterns\Structural\Composite\Tests;
|
||||
|
||||
use DesignPatterns\Structural\Composite;
|
||||
use DesignPatterns\Structural\Composite\Form;
|
||||
use DesignPatterns\Structural\Composite\TextElement;
|
||||
use DesignPatterns\Structural\Composite\InputElement;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class CompositeTest extends TestCase
|
||||
{
|
||||
public function testRender()
|
||||
{
|
||||
$form = new Composite\Form();
|
||||
$form->addElement(new Composite\TextElement('Email:'));
|
||||
$form->addElement(new Composite\InputElement());
|
||||
$embed = new Composite\Form();
|
||||
$embed->addElement(new Composite\TextElement('Password:'));
|
||||
$embed->addElement(new Composite\InputElement());
|
||||
$form = new Form();
|
||||
$form->addElement(new TextElement('Email:'));
|
||||
$form->addElement(new InputElement());
|
||||
$embed = new Form();
|
||||
$embed->addElement(new TextElement('Password:'));
|
||||
$embed->addElement(new InputElement());
|
||||
$form->addElement($embed);
|
||||
|
||||
// This is just an example, in a real world scenario it is important to remember that web browsers do not
|
||||
|
@ -4,10 +4,7 @@ namespace DesignPatterns\Structural\Composite;
|
||||
|
||||
class TextElement implements Renderable
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $text;
|
||||
private string $text;
|
||||
|
||||
public function __construct(string $text)
|
||||
{
|
||||
|
@ -4,10 +4,7 @@ namespace DesignPatterns\Structural\DataMapper;
|
||||
|
||||
class StorageAdapter
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $data = [];
|
||||
private array $data = [];
|
||||
|
||||
public function __construct(array $data)
|
||||
{
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace DesignPatterns\Structural\DataMapper\Tests;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use DesignPatterns\Structural\DataMapper\StorageAdapter;
|
||||
use DesignPatterns\Structural\DataMapper\User;
|
||||
use DesignPatterns\Structural\DataMapper\UserMapper;
|
||||
@ -21,7 +22,7 @@ class DataMapperTest extends TestCase
|
||||
|
||||
public function testWillNotMapInvalidData()
|
||||
{
|
||||
$this->expectException(\InvalidArgumentException::class);
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
|
||||
$storage = new StorageAdapter([]);
|
||||
$mapper = new UserMapper($storage);
|
||||
|
@ -4,15 +4,8 @@ namespace DesignPatterns\Structural\DataMapper;
|
||||
|
||||
class User
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $username;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $email;
|
||||
private string $username;
|
||||
private string $email;
|
||||
|
||||
public static function fromState(array $state): User
|
||||
{
|
||||
@ -32,18 +25,12 @@ class User
|
||||
$this->email = $email;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getUsername()
|
||||
public function getUsername(): string
|
||||
{
|
||||
return $this->username;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getEmail()
|
||||
public function getEmail(): string
|
||||
{
|
||||
return $this->email;
|
||||
}
|
||||
|
@ -2,16 +2,12 @@
|
||||
|
||||
namespace DesignPatterns\Structural\DataMapper;
|
||||
|
||||
use InvalidArgumentException;
|
||||
|
||||
class UserMapper
|
||||
{
|
||||
/**
|
||||
* @var StorageAdapter
|
||||
*/
|
||||
private $adapter;
|
||||
private StorageAdapter $adapter;
|
||||
|
||||
/**
|
||||
* @param StorageAdapter $storage
|
||||
*/
|
||||
public function __construct(StorageAdapter $storage)
|
||||
{
|
||||
$this->adapter = $storage;
|
||||
@ -22,17 +18,13 @@ class UserMapper
|
||||
* in memory. Normally this kind of logic will be implemented using the Repository pattern.
|
||||
* However the important part is in mapRowToUser() below, that will create a business object from the
|
||||
* data fetched from storage
|
||||
*
|
||||
* @param int $id
|
||||
*
|
||||
* @return User
|
||||
*/
|
||||
public function findById(int $id): User
|
||||
{
|
||||
$result = $this->adapter->find($id);
|
||||
|
||||
if ($result === null) {
|
||||
throw new \InvalidArgumentException("User #$id not found");
|
||||
throw new InvalidArgumentException("User #$id not found");
|
||||
}
|
||||
|
||||
return $this->mapRowToUser($result);
|
||||
|
@ -4,10 +4,7 @@ namespace DesignPatterns\Structural\Decorator;
|
||||
|
||||
abstract class BookingDecorator implements Booking
|
||||
{
|
||||
/**
|
||||
* @var Booking
|
||||
*/
|
||||
protected $booking;
|
||||
protected Booking $booking;
|
||||
|
||||
public function __construct(Booking $booking)
|
||||
{
|
||||
|
@ -4,25 +4,10 @@ namespace DesignPatterns\Structural\DependencyInjection;
|
||||
|
||||
class DatabaseConfiguration
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $host;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $port;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $username;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $password;
|
||||
private string $host;
|
||||
private int $port;
|
||||
private string $username;
|
||||
private string $password;
|
||||
|
||||
public function __construct(string $host, int $port, string $username, string $password)
|
||||
{
|
||||
|
@ -4,14 +4,8 @@ namespace DesignPatterns\Structural\DependencyInjection;
|
||||
|
||||
class DatabaseConnection
|
||||
{
|
||||
/**
|
||||
* @var DatabaseConfiguration
|
||||
*/
|
||||
private $configuration;
|
||||
private DatabaseConfiguration $configuration;
|
||||
|
||||
/**
|
||||
* @param DatabaseConfiguration $config
|
||||
*/
|
||||
public function __construct(DatabaseConfiguration $config)
|
||||
{
|
||||
$this->configuration = $config;
|
||||
|
@ -4,20 +4,9 @@ namespace DesignPatterns\Structural\Facade;
|
||||
|
||||
class Facade
|
||||
{
|
||||
/**
|
||||
* @var OperatingSystem
|
||||
*/
|
||||
private $os;
|
||||
private OperatingSystem $os;
|
||||
private Bios $bios;
|
||||
|
||||
/**
|
||||
* @var Bios
|
||||
*/
|
||||
private $bios;
|
||||
|
||||
/**
|
||||
* @param Bios $bios
|
||||
* @param OperatingSystem $os
|
||||
*/
|
||||
public function __construct(Bios $bios, OperatingSystem $os)
|
||||
{
|
||||
$this->bios = $bios;
|
||||
|
@ -4,20 +4,9 @@ namespace DesignPatterns\Structural\FluentInterface;
|
||||
|
||||
class Sql
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $fields = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $from = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $where = [];
|
||||
private array $fields = [];
|
||||
private array $from = [];
|
||||
private array $where = [];
|
||||
|
||||
public function select(array $fields): Sql
|
||||
{
|
||||
|
@ -11,10 +11,8 @@ class Character implements Text
|
||||
/**
|
||||
* Any state stored by the concrete flyweight must be independent of its context.
|
||||
* For flyweights representing characters, this is usually the corresponding character code.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $name;
|
||||
private string $name;
|
||||
|
||||
public function __construct(string $name)
|
||||
{
|
||||
|
@ -7,9 +7,10 @@ use PHPUnit\Framework\TestCase;
|
||||
|
||||
class FlyweightTest extends TestCase
|
||||
{
|
||||
private $characters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k',
|
||||
private array $characters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k',
|
||||
'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'];
|
||||
private $fonts = ['Arial', 'Times New Roman', 'Verdana', 'Helvetica'];
|
||||
|
||||
private array $fonts = ['Arial', 'Times New Roman', 'Verdana', 'Helvetica'];
|
||||
|
||||
public function testFlyweight()
|
||||
{
|
||||
|
@ -2,16 +2,18 @@
|
||||
|
||||
namespace DesignPatterns\Structural\Flyweight;
|
||||
|
||||
use Countable;
|
||||
|
||||
/**
|
||||
* A factory manages shared flyweights. Clients should not instantiate them directly,
|
||||
* but let the factory take care of returning existing objects or creating new ones.
|
||||
*/
|
||||
class TextFactory implements \Countable
|
||||
class TextFactory implements Countable
|
||||
{
|
||||
/**
|
||||
* @var Text[]
|
||||
*/
|
||||
private $charPool = [];
|
||||
private array $charPool = [];
|
||||
|
||||
public function get(string $name): Text
|
||||
{
|
||||
|
@ -4,10 +4,7 @@ namespace DesignPatterns\Structural\Flyweight;
|
||||
|
||||
class Word implements Text
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $name;
|
||||
private string $name;
|
||||
|
||||
public function __construct(string $name)
|
||||
{
|
||||
|
@ -4,10 +4,7 @@ namespace DesignPatterns\Structural\Proxy;
|
||||
|
||||
class BankAccountProxy extends HeavyBankAccount implements BankAccount
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $balance;
|
||||
private ?int $balance = null;
|
||||
|
||||
public function getBalance(): int
|
||||
{
|
||||
|
@ -7,7 +7,7 @@ class HeavyBankAccount implements BankAccount
|
||||
/**
|
||||
* @var int[]
|
||||
*/
|
||||
private $transactions = [];
|
||||
private array $transactions = [];
|
||||
|
||||
public function deposit(int $amount)
|
||||
{
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
namespace DesignPatterns\Structural\Registry;
|
||||
|
||||
use InvalidArgumentException;
|
||||
|
||||
abstract class Registry
|
||||
{
|
||||
const LOGGER = 'logger';
|
||||
@ -12,19 +14,16 @@ abstract class Registry
|
||||
*
|
||||
* @var Service[]
|
||||
*/
|
||||
private static $services = [];
|
||||
private static array $services = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private static $allowedKeys = [
|
||||
private static array $allowedKeys = [
|
||||
self::LOGGER,
|
||||
];
|
||||
|
||||
public static function set(string $key, Service $value)
|
||||
{
|
||||
if (!in_array($key, self::$allowedKeys)) {
|
||||
throw new \InvalidArgumentException('Invalid key given');
|
||||
throw new InvalidArgumentException('Invalid key given');
|
||||
}
|
||||
|
||||
self::$services[$key] = $value;
|
||||
@ -33,7 +32,7 @@ abstract class Registry
|
||||
public static function get(string $key): Service
|
||||
{
|
||||
if (!in_array($key, self::$allowedKeys) || !isset(self::$services[$key])) {
|
||||
throw new \InvalidArgumentException('Invalid key given');
|
||||
throw new InvalidArgumentException('Invalid key given');
|
||||
}
|
||||
|
||||
return self::$services[$key];
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace DesignPatterns\Structural\Registry\Tests;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use DesignPatterns\Structural\Registry\Registry;
|
||||
use DesignPatterns\Structural\Registry\Service;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
@ -9,7 +10,10 @@ use PHPUnit\Framework\TestCase;
|
||||
|
||||
class RegistryTest extends TestCase
|
||||
{
|
||||
private $service;
|
||||
/**
|
||||
* @var Service
|
||||
*/
|
||||
private MockObject $service;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
@ -18,7 +22,6 @@ class RegistryTest extends TestCase
|
||||
|
||||
public function testSetAndGetLogger()
|
||||
{
|
||||
/** @noinspection PhpParamsInspection */
|
||||
Registry::set(Registry::LOGGER, $this->service);
|
||||
|
||||
$this->assertSame($this->service, Registry::get(Registry::LOGGER));
|
||||
@ -26,7 +29,7 @@ class RegistryTest extends TestCase
|
||||
|
||||
public function testThrowsExceptionWhenTryingToSetInvalidKey()
|
||||
{
|
||||
$this->expectException(\InvalidArgumentException::class);
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
|
||||
Registry::set('foobar', $this->service);
|
||||
}
|
||||
@ -40,7 +43,7 @@ class RegistryTest extends TestCase
|
||||
*/
|
||||
public function testThrowsExceptionWhenTryingToGetNotSetKey()
|
||||
{
|
||||
$this->expectException(\InvalidArgumentException::class);
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
|
||||
Registry::get(Registry::LOGGER);
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
{
|
||||
"name": "domnikl/design-patterns-php",
|
||||
"description": "Sample code for several design patterns in PHP",
|
||||
"license": ["MIT"],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Dominik Liebler",
|
||||
@ -9,7 +10,7 @@
|
||||
],
|
||||
"minimum-stability": "stable",
|
||||
"require": {
|
||||
"php": ">=7.2",
|
||||
"php": ">=7.4",
|
||||
"psr/http-message": "^1.0",
|
||||
"ext-json": "*"
|
||||
},
|
||||
@ -18,11 +19,10 @@
|
||||
"squizlabs/php_codesniffer": "^3",
|
||||
"flyeralarm/php-code-validator": "^2.2",
|
||||
"vimeo/psalm": "^3.4",
|
||||
"psalm/plugin-phpunit": "^0.7.0"
|
||||
"psalm/plugin-phpunit": "^0.7.0",
|
||||
"rector/rector": "^0.6.1"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"DesignPatterns\\": ""
|
||||
}
|
||||
"classmap": ["Behavioral", "Creational", "Structural", "More"]
|
||||
}
|
||||
}
|
||||
|
2388
composer.lock
generated
2388
composer.lock
generated
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user