update deps & install rector

This commit is contained in:
Dominik Liebler 2019-12-14 12:50:05 +01:00
parent 04acce6759
commit 579a5ac946
No known key found for this signature in database
GPG Key ID: DCE4AADEA26FD47B
87 changed files with 2432 additions and 786 deletions

View File

@ -3,9 +3,7 @@ language: php
sudo: false
php:
- 7.2
- 7.3
- 7.4snapshot
- 7.4
matrix:
fast_finish: true

View File

@ -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;
}

View File

@ -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',

View File

@ -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

View File

@ -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
{

View File

@ -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)
{

View File

@ -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)
{

View File

@ -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)
{

View File

@ -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) {

View File

@ -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)
{

View File

@ -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)
{

View File

@ -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;

View File

@ -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');

View File

@ -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)
{

View File

@ -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;
}

View File

@ -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');
}
}

View File

@ -7,10 +7,7 @@ namespace DesignPatterns\Behavioral\Memento;
*/
class Ticket
{
/**
* @var State
*/
private $currentState;
private State $currentState;
public function __construct()
{

View File

@ -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;

View File

@ -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);
}

View File

@ -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)
{

View File

@ -7,7 +7,7 @@ class AndSpecification implements Specification
/**
* @var Specification[]
*/
private $specifications;
private array $specifications;
/**
* @param Specification[] $specifications

View File

@ -4,10 +4,7 @@ namespace DesignPatterns\Behavioral\Specification;
class Item
{
/**
* @var float
*/
private $price;
private float $price;
public function __construct(float $price)
{

View File

@ -4,10 +4,7 @@ namespace DesignPatterns\Behavioral\Specification;
class NotSpecification implements Specification
{
/**
* @var Specification
*/
private $specification;
private Specification $specification;
public function __construct(Specification $specification)
{

View File

@ -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;
}
}

View File

@ -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;

View File

@ -4,10 +4,7 @@ namespace DesignPatterns\Behavioral\State;
class OrderContext
{
/**
* @var State
*/
private $state;
private State $state;
public static function create(): OrderContext
{

View File

@ -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']);

View File

@ -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;
}

View File

@ -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'];

View File

@ -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";
}

View File

@ -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;
}

View File

@ -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(

View File

@ -4,10 +4,7 @@ namespace DesignPatterns\Behavioral\Visitor;
class Group implements Role
{
/**
* @var string
*/
private $name;
private string $name;
public function __construct(string $name)
{

View File

@ -7,7 +7,7 @@ class RecordingVisitor implements RoleVisitor
/**
* @var Role[]
*/
private $visited = [];
private array $visited = [];
public function visitGroup(Group $role)
{

View File

@ -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]);

View File

@ -4,10 +4,7 @@ namespace DesignPatterns\Behavioral\Visitor;
class User implements Role
{
/**
* @var string
*/
private $name;
private string $name;
public function __construct(string $name)
{

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -4,10 +4,7 @@ namespace DesignPatterns\Creational\FactoryMethod;
class FileLogger implements Logger
{
/**
* @var string
*/
private $filePath;
private string $filePath;
public function __construct(string $filePath)
{

View File

@ -4,10 +4,7 @@ namespace DesignPatterns\Creational\FactoryMethod;
class FileLoggerFactory implements LoggerFactory
{
/**
* @var string
*/
private $filePath;
private string $filePath;
public function __construct(string $filePath)
{

View File

@ -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

View File

@ -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)

View File

@ -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
{

View File

@ -4,10 +4,7 @@ namespace DesignPatterns\Creational\Prototype;
class BarBookPrototype extends BookPrototype
{
/**
* @var string
*/
protected $category = 'Bar';
protected string $category = 'Bar';
public function __clone()
{

View File

@ -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;
}

View File

@ -4,10 +4,7 @@ namespace DesignPatterns\Creational\Prototype;
class FooBookPrototype extends BookPrototype
{
/**
* @var string
*/
protected $category = 'Foo';
protected string $category = 'Foo';
public function __clone()
{

View File

@ -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)

View File

@ -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');
}
}

View File

@ -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');
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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)
{

View File

@ -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;

View File

@ -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');
}
}
}

View File

@ -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');
}
}
}

View File

@ -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]);

View File

@ -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);

View File

@ -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));

View File

@ -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;

View File

@ -8,10 +8,7 @@ use PHPUnit\Framework\TestCase;
class ServiceLocatorTest extends TestCase
{
/**
* @var ServiceLocator
*/
private $serviceLocator;
private ServiceLocator $serviceLocator;
public function setUp(): void
{

View File

@ -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
{

View File

@ -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()
{

View File

@ -4,10 +4,7 @@ namespace DesignPatterns\Structural\Adapter;
class PaperBook implements Book
{
/**
* @var int
*/
private $page;
private int $page;
public function open()
{

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -4,10 +4,7 @@ namespace DesignPatterns\Structural\Composite;
class TextElement implements Renderable
{
/**
* @var string
*/
private $text;
private string $text;
public function __construct(string $text)
{

View File

@ -4,10 +4,7 @@ namespace DesignPatterns\Structural\DataMapper;
class StorageAdapter
{
/**
* @var array
*/
private $data = [];
private array $data = [];
public function __construct(array $data)
{

View File

@ -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);

View File

@ -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;
}

View File

@ -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);

View File

@ -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)
{

View File

@ -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)
{

View File

@ -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;

View File

@ -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;

View File

@ -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
{

View File

@ -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)
{

View File

@ -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()
{

View File

@ -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
{

View File

@ -4,10 +4,7 @@ namespace DesignPatterns\Structural\Flyweight;
class Word implements Text
{
/**
* @var string
*/
private $name;
private string $name;
public function __construct(string $name)
{

View File

@ -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
{

View File

@ -7,7 +7,7 @@ class HeavyBankAccount implements BankAccount
/**
* @var int[]
*/
private $transactions = [];
private array $transactions = [];
public function deposit(int $amount)
{

View File

@ -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];

View File

@ -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);
}

View File

@ -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

File diff suppressed because it is too large Load Diff