├── .gitignore ├── LICENSE ├── README.md ├── composer.json ├── composer.lock ├── demo.jpg └── src ├── Behavioral ├── ChainOfResponsibility │ ├── ApiMiddleware.php │ ├── App.php │ ├── GetMiddleware.php │ ├── Middleware.php │ ├── MiddlewareError.php │ ├── Request.php │ ├── Response.php │ ├── index.php │ └── server.sh ├── Command │ ├── Client.php │ ├── Command.php │ ├── CreateListing.php │ ├── DeleteListing.php │ ├── ListingRepository.php │ └── demo.php ├── Iterator │ ├── Employee.php │ ├── Team.php │ ├── TeamIterator.php │ └── demo.php ├── NullObject │ ├── ArrayCache.php │ ├── Cache.php │ └── DummyCache.php ├── Observer │ ├── Communicator.php │ ├── Employee.php │ ├── HumanResources.php │ └── demo.php ├── Specification │ ├── AndSpecification.php │ ├── Candidate.php │ ├── ConvictedSpecification.php │ ├── Education.php │ ├── MaxAgeSpecification.php │ ├── NotSpecification.php │ ├── OrSpecification.php │ ├── RecentGraduateSpecification.php │ ├── Specification.php │ ├── StudentSpecification.php │ ├── WorkExperience.php │ ├── WorkExperienceSpecification.php │ └── demo.php ├── State │ ├── Angry.php │ ├── Happy.php │ ├── Mood.php │ ├── Neutral.php │ ├── Person.php │ └── demo.php ├── Strategy │ ├── Context.php │ ├── JSONFormatter.php │ ├── OutputFormatter.php │ ├── StringFormatter.php │ ├── XMLFormatter.php │ └── demo.php ├── TemplateMethod │ ├── ActionMovie.php │ ├── ComedyMovie.php │ ├── Movie.php │ └── demo.php └── Visitor │ ├── SickLeave.php │ ├── SickLeaveReport.php │ ├── Student.php │ ├── University.php │ ├── Visitable.php │ ├── Visitor.php │ └── demo.php ├── Creational ├── AbstractFactory │ ├── DeviceFactory.php │ ├── DisplayFactory.php │ ├── IndoorDisplay.php │ ├── IndoorIot.php │ ├── IndoorProduct.php │ ├── IotFactory.php │ ├── OutdoorDisplay.php │ ├── OutdoorIot.php │ ├── OutdoorProduct.php │ └── demo.php ├── Builder │ ├── Device.php │ ├── DeviceBuilder.php │ ├── Director.php │ ├── InteractiveMirror.php │ ├── InteractiveMirrorBuilder.php │ └── demo.php ├── FactoryMethod │ ├── AudioBox.php │ ├── Box.php │ ├── BoxFactory.php │ ├── Factory.php │ ├── FileItem.php │ ├── ImgBox.php │ ├── VideoBox.php │ └── demo.php ├── Prototype │ ├── Computer.php │ ├── Device.php │ ├── DeviceGroup.php │ └── demo.php └── Singleton │ └── ActiveUser.php └── Structural ├── Adapter ├── .env.example ├── AWSFileStorage.php ├── Client.php ├── File.php ├── FileAdapter.php ├── LocalFileStorage.php ├── assets │ └── logo.png ├── index.php ├── server.sh └── storage │ └── .gitkeep ├── Bridge ├── Blurred.php ├── Content.php ├── Display.php ├── Image.php ├── Standard.php ├── Video.php └── demo.php ├── Composite ├── Budgeted.php ├── BudgetedComposite.php ├── Department.php ├── Employee.php └── demo.php ├── Decorator ├── Product.php ├── ProductDecorator.php ├── Shirt.php ├── SummerSale.php ├── TV.php ├── WinterSale.php └── demo.php ├── DependencyInjection ├── Storage.php ├── User.php ├── UserStorage.php └── UserTest.php ├── Facade ├── Image.php └── demo.php ├── FluentInterface ├── QueryBuilder.php └── demo.php ├── Flyweight ├── Device.php ├── DeviceStorage.php ├── DeviceType.php ├── DeviceTypeFactory.php ├── Generator.php └── demo.php └── Proxy ├── AuthFile.php ├── File.php ├── FileProvider.php ├── User.php └── demo.php /.gitignore: -------------------------------------------------------------------------------- 1 | vendor 2 | .idea 3 | .env -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Jakub Kapuscik 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Design Patterns 2 | 3 | This project is set of simple examples of usage of different design patterns in a real world scenarios. Each one have a short description and guideline: 4 | - [Factory Method](https://medium.com/@j.kapuscik2/getting-started-with-design-patterns-in-php-4d451ccdfb71) 5 | - [src/Creational Patterns](https://medium.com/@j.kapuscik2/src/Creational-design-patterns-in-php-db365d3245ce) 6 | - [Observer](https://medium.com/@j.kapuscik2/observer-pattern-in-php-2ba240f89fb2) 7 | - [Iterator](https://medium.com/@j.kapuscik2/iterator-pattern-in-php-b7624f6bdbcf) 8 | - [State & Strategy](https://medium.com/@j.kapuscik2/state-strategy-design-patterns-by-example-f57ebd7b6211) 9 | - [Template Method](https://medium.com/@j.kapuscik2/template-method-pattern-in-php-6116fd7e8ccc?source=friends_link&sk=ac4c483446bd5a5323c09a662bd54116) 10 | - [Flyweight](https://medium.com/swlh/flyweight-design-pattern-in-php-edcda0486fb0?source=friends_link&sk=a0fa3083d5afd7e41af8a4f7a1df05f1) 11 | - [Proxy](https://medium.com/better-programming/proxy-design-pattern-and-how-to-use-it-acd0f11e5330) 12 | - [Decorator](https://medium.com/better-programming/decorator-c04fae63dfff) 13 | - [Dependency Injection](https://medium.com/better-programming/dependency-injection-8f09a93ec995) 14 | - [Composite](https://medium.com/swlh/composite-908878748d0e) 15 | - [Adapter](https://medium.com/swlh/building-cloud-storage-application-with-adapter-design-pattern-8b0105a1bda7) 16 | - [Facade](https://medium.com/better-programming/what-is-facade-design-pattern-67cb09ce35d4) 17 | - [Bridge](https://medium.com/better-programming/what-is-bridge-design-pattern-89bfa581fbd3) 18 | - [Chain of Responsibility](https://medium.com/@j.kapuscik2/what-is-chain-of-responsibility-design-pattern-ff4d22abd124) 19 | - [Visitor](https://medium.com/@j.kapuscik2/what-is-visitor-design-pattern-8451fb75876) 20 | - [Command](https://medium.com/@j.kapuscik2/what-is-cqrs-command-design-pattern-5d400fd9f93a) 21 | - [Null Object](https://medium.com/@j.kapuscik2/what-is-null-object-design-pattern-f3b4d3d28636) 22 | - [Fluent Interface](https://medium.com/@j.kapuscik2/what-is-the-fluent-interface-design-pattern-2797645b2a2e) 23 | - [Specification](https://medium.com/@j.kapuscik2/what-is-the-specification-design-pattern-4051dd9e71c3) 24 | 25 | ### Following patterns have so far been described: 26 | 27 | #### Creational: 28 | 1. [Factory Method](/src/Creational/FactoryMethod) 29 | 2. [Abstract Factory](/src/Creational/AbstractFactory) 30 | 3. [Singleton](/src/Creational/Singleton) 31 | 4. [Builder](/src/Creational/Builder) 32 | 5. [Prototype](/src/Creational/Prototype) 33 | 34 | #### Behavioral: 35 | 1. [Iterator](src/Behavioral/Iterator) 36 | 2. [Observer](src/Behavioral/Observer) 37 | 3. [State](src/Behavioral/State) 38 | 4. [Strategy](src/Behavioral/Strategy) 39 | 5. [Template Method](src/Behavioral/TemplateMethod) 40 | 6. [Chain of Responsibility](src/Behavioral/ChainOfResponsibility) 41 | 7. [Visitor](src/Behavioral/Visitor) 42 | 8. [Command](src/Behavioral/Command) 43 | 9. [Null Object](src/Behavioral/NullObject) 44 | 10. [Specification](src/Behavioral/Specification) 45 | 46 | #### Structural: 47 | 1. [Adapter](src/Structural/Adapter) 48 | 2. [Decorator](src/Structural/Decorator) 49 | 3. [Proxy](src/Structural/Proxy) 50 | 4. [Dependency Injection](src/Structural/DependencyInjection) 51 | 5. [Facade](src/Structural/Facade) 52 | 6. [Composite](src/Structural/Composite) 53 | 7. [Bridge](src/Structural/Bridge) 54 | 8. [Flyweight](src/Structural/Flyweight) 55 | 9. [Fluent Interface](src/Structural/FluentInterface) 56 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "kapusj01/design_patterns", 3 | "authors": [ 4 | { 5 | "name": "Jakub Kapuscik", 6 | "email": "j.kapuscik2@gmail.com" 7 | } 8 | ], 9 | "require": { 10 | "php": "^8.2", 11 | "phpunit/phpunit": "^10.2", 12 | "symfony/dotenv": "^6.3", 13 | "aws/aws-sdk-php": "^3.275" 14 | }, 15 | "autoload": { 16 | "psr-4": { "App\\": "src/" } 17 | }, 18 | "require-dev": { 19 | "friendsofphp/php-cs-fixer": "^3.21" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /demo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jkapuscik2/design-patterns-php/824df7fd86743fa6aaae0cae9ed99cfa1318409a/demo.jpg -------------------------------------------------------------------------------- /src/Behavioral/ChainOfResponsibility/ApiMiddleware.php: -------------------------------------------------------------------------------- 1 | hasParam(self::API_KEY_NAME) 16 | && in_array($request->getParam(self::API_KEY_NAME), self::API_KEYS)) { 17 | 18 | return parent::process($request); 19 | } else { 20 | throw new MiddlewareError("Api key validation error"); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Behavioral/ChainOfResponsibility/App.php: -------------------------------------------------------------------------------- 1 | request = new Request($_GET, $_SERVER); 13 | $this->setMiddleware(); 14 | } 15 | 16 | private function setMiddleware(): void 17 | { 18 | $this->middleware = new GetMiddleware(); 19 | $this->middleware->setNext(new ApiMiddleware()); 20 | } 21 | 22 | public function run(): string 23 | { 24 | if ($this->middleware->process($this->request)) { 25 | return (new Response($this->request))->handle(); 26 | } 27 | 28 | return ""; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Behavioral/ChainOfResponsibility/GetMiddleware.php: -------------------------------------------------------------------------------- 1 | hasServerParam($this->methodKey) 13 | && $request->getServerParam($this->methodKey) === $this->allowedMethod) { 14 | 15 | return parent::process($request); 16 | } else { 17 | throw new MiddlewareError("Only GET requests allowed"); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Behavioral/ChainOfResponsibility/Middleware.php: -------------------------------------------------------------------------------- 1 | next = $middleware; 12 | 13 | return $middleware; 14 | } 15 | 16 | public function process(Request $request): bool 17 | { 18 | if (isset($this->next)) { 19 | return $this->next->process($request); 20 | } 21 | return true; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Behavioral/ChainOfResponsibility/MiddlewareError.php: -------------------------------------------------------------------------------- 1 | params[$name]; 14 | } 15 | 16 | public function getParams(): array 17 | { 18 | return $this->params; 19 | } 20 | 21 | public function hasParam(string $name): bool 22 | { 23 | return array_key_exists($name, $this->params); 24 | } 25 | 26 | public function getServerParam(string $name) 27 | { 28 | return $this->server[$name]; 29 | } 30 | 31 | public function hasServerParam(string $name): bool 32 | { 33 | return array_key_exists($name, $this->server); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Behavioral/ChainOfResponsibility/Response.php: -------------------------------------------------------------------------------- 1 | self::CODE_OK, 21 | "message" => "Request proceeded correctly", 22 | "params" => $this->request->getParams() 23 | ]); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Behavioral/ChainOfResponsibility/index.php: -------------------------------------------------------------------------------- 1 | run(); 9 | -------------------------------------------------------------------------------- /src/Behavioral/ChainOfResponsibility/server.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | php -S localhost:8000 4 | -------------------------------------------------------------------------------- /src/Behavioral/Command/Client.php: -------------------------------------------------------------------------------- 1 | listingRepository, $title, $content, $author); 14 | $command->handle(); 15 | } 16 | 17 | public function deleteListing(string $listingUuid): void 18 | { 19 | $command = new DeleteListing($this->listingRepository, $listingUuid); 20 | $command->handle(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Behavioral/Command/Command.php: -------------------------------------------------------------------------------- 1 | title) < self::MIN_TITLE_LENGTH) { 20 | throw new LengthException(sprintf( 21 | "Title is too short. Must be at least %d characters", 22 | self::MIN_TITLE_LENGTH 23 | )); 24 | } 25 | if (mb_strlen($this->content) < self::MIN_CONTENT_LENGTH) { 26 | throw new LengthException(sprintf( 27 | "Content is too short. Must be at least %d characters", 28 | self::MIN_CONTENT_LENGTH 29 | )); 30 | } 31 | if (mb_strlen($this->author) < self::MIN_AUTHOR_LENGTH) { 32 | throw new LengthException(sprintf( 33 | "Author name is too short. Must be at least %d characters", 34 | self::MIN_AUTHOR_LENGTH 35 | )); 36 | } 37 | } 38 | 39 | public function handle(): void 40 | { 41 | $this->validate(); 42 | $this->repository->create($this->title, $this->content, $this->author); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Behavioral/Command/DeleteListing.php: -------------------------------------------------------------------------------- 1 | repository->delete($this->listingUid); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Behavioral/Command/ListingRepository.php: -------------------------------------------------------------------------------- 1 | createListing( 9 | "New job listing", 10 | "This is a content of a listing", 11 | "Company" 12 | ); 13 | $client->deleteListing("Unique id"); 14 | -------------------------------------------------------------------------------- /src/Behavioral/Iterator/Employee.php: -------------------------------------------------------------------------------- 1 | name; 16 | } 17 | 18 | public function getPosition(): string 19 | { 20 | return $this->position; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Behavioral/Iterator/Team.php: -------------------------------------------------------------------------------- 1 | teams = new SplObjectStorage(); 18 | } 19 | 20 | public function addTeam(Team $subordinate): void 21 | { 22 | $this->teams->attach($subordinate); 23 | } 24 | 25 | public function detachTeam(Team $subordinate): void 26 | { 27 | $this->teams->detach($subordinate); 28 | } 29 | 30 | public function getTeams(): SplObjectStorage 31 | { 32 | return $this->teams; 33 | } 34 | 35 | public function getIterator(): TeamIterator 36 | { 37 | return new TeamIterator($this); 38 | } 39 | 40 | public function count(): int 41 | { 42 | return count(new TeamIterator($this)); 43 | } 44 | 45 | public function getName(): string 46 | { 47 | return $this->name; 48 | } 49 | 50 | public function getLeader(): Employee 51 | { 52 | return $this->leader; 53 | } 54 | 55 | public function printSummary(): void 56 | { 57 | echo $this->leader->getPosition() . ": " . $this->leader->getName() . " manages " . count($this) . " teams" . PHP_EOL; 58 | 59 | foreach ($this as $team) { 60 | echo $team->getName() . " led by: " . $team->getLeader()->getName() . PHP_EOL; 61 | } 62 | echo PHP_EOL; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Behavioral/Iterator/TeamIterator.php: -------------------------------------------------------------------------------- 1 | addTeam($employee); 16 | $this->position = 0; 17 | } 18 | 19 | protected function addTeam(Team $employee): void 20 | { 21 | foreach ($employee->getTeams() as $member) { 22 | $this->teams[] = $member; 23 | $this->addTeam($member); 24 | } 25 | } 26 | 27 | public function current(): Team 28 | { 29 | return $this->teams[$this->position]; 30 | } 31 | 32 | public function next(): void 33 | { 34 | ++$this->position; 35 | } 36 | 37 | public function key(): int 38 | { 39 | return $this->position; 40 | } 41 | 42 | public function valid(): bool 43 | { 44 | return isset($this->teams[$this->position]); 45 | } 46 | 47 | public function rewind(): void 48 | { 49 | $this->position = 0; 50 | } 51 | 52 | public function count(): int 53 | { 54 | return count($this->teams); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Behavioral/Iterator/demo.php: -------------------------------------------------------------------------------- 1 | addTeam($teamA); 13 | $tech->addTeam($teamB); 14 | $ceo->addTeam($tech); 15 | 16 | $ceo->printSummary(); 17 | 18 | $teamC = new Team("Team C", new Employee("Jan", 'Team Leader')); 19 | $tech->addTeam($teamC); 20 | 21 | $ceo->printSummary(); 22 | 23 | $ceo->detachTeam($teamC); 24 | $tech->printSummary(); 25 | -------------------------------------------------------------------------------- /src/Behavioral/NullObject/ArrayCache.php: -------------------------------------------------------------------------------- 1 | has($key)) { 12 | return $this->data[$key]; 13 | } 14 | return false; 15 | } 16 | 17 | public function set(string $key, string $data): void 18 | { 19 | $this->data[$key] = $data; 20 | } 21 | 22 | public function has(string $key): bool 23 | { 24 | return array_key_exists($key, $this->data); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Behavioral/NullObject/Cache.php: -------------------------------------------------------------------------------- 1 | employees = new SplObjectStorage(); 16 | } 17 | 18 | public function attach(SplObserver $employee): void 19 | { 20 | $this->employees->attach($employee); 21 | } 22 | 23 | public function detach(SplObserver $employee): void 24 | { 25 | $this->employees->detach($employee); 26 | } 27 | 28 | public function inform(string $message): void 29 | { 30 | $this->notify($message); 31 | } 32 | 33 | public function notify(string $message = ""): void 34 | { 35 | foreach ($this->employees as $employee) { 36 | /** 37 | * @var $employee Employee 38 | */ 39 | $employee->update($this, $message); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Behavioral/Observer/Employee.php: -------------------------------------------------------------------------------- 1 | sendEmail($message); 17 | } 18 | 19 | protected function sendEmail(string $message): void 20 | { 21 | echo "Sending email to: " . $this->email . " - Hello " . $this->name . ", " . $message . PHP_EOL; 22 | } 23 | 24 | public function getName(): string 25 | { 26 | return $this->name; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Behavioral/Observer/HumanResources.php: -------------------------------------------------------------------------------- 1 | communicator = new Communicator(); 12 | 13 | foreach ($employees as $employee) { 14 | $this->communicator->attach($employee); 15 | } 16 | } 17 | 18 | public function inform(string $message): void 19 | { 20 | $this->communicator->inform($message); 21 | } 22 | 23 | public function layOf(Employee $employee): void 24 | { 25 | $this->communicator->detach($employee); 26 | } 27 | 28 | public function employ(Employee $employee): void 29 | { 30 | $this->communicator->attach($employee); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Behavioral/Observer/demo.php: -------------------------------------------------------------------------------- 1 | inform("Some important news"); 15 | 16 | $software = new Employee("Ben", "ben@gmail.com"); 17 | $hr->inform("New employee: " . $software->getName()); 18 | $hr->employ($software); 19 | 20 | $hr->layOf($software); 21 | $hr->inform("Employee was laid off: " . $software->getName()); 22 | -------------------------------------------------------------------------------- /src/Behavioral/Specification/AndSpecification.php: -------------------------------------------------------------------------------- 1 | specifications = $specifications; 12 | } 13 | 14 | public function isSatisfiedBy(Candidate $candidate): bool 15 | { 16 | foreach ($this->specifications as $specification) { 17 | if (! $specification->isSatisfiedBy($candidate)) { 18 | return false; 19 | } 20 | } 21 | 22 | return true; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Behavioral/Specification/Candidate.php: -------------------------------------------------------------------------------- 1 | age; 14 | } 15 | 16 | public function getWorkExperience(): array 17 | { 18 | return $this->workExperience; 19 | } 20 | 21 | public function getEducation(): array 22 | { 23 | return $this->education; 24 | } 25 | 26 | public function isConvicted(): bool 27 | { 28 | return $this->isConvicted; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/Behavioral/Specification/ConvictedSpecification.php: -------------------------------------------------------------------------------- 1 | isConvicted(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Behavioral/Specification/Education.php: -------------------------------------------------------------------------------- 1 | end; 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/Behavioral/Specification/MaxAgeSpecification.php: -------------------------------------------------------------------------------- 1 | getAge() <= $this->maxAge; 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/Behavioral/Specification/NotSpecification.php: -------------------------------------------------------------------------------- 1 | specification->isSatisfiedBy($candidate); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Behavioral/Specification/OrSpecification.php: -------------------------------------------------------------------------------- 1 | specifications = $specifications; 12 | } 13 | 14 | public function isSatisfiedBy(Candidate $candidate): bool 15 | { 16 | foreach ($this->specifications as $specification) { 17 | if ($specification->isSatisfiedBy($candidate)) { 18 | return true; 19 | } 20 | } 21 | 22 | return false; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Behavioral/Specification/RecentGraduateSpecification.php: -------------------------------------------------------------------------------- 1 | sub(new DateInterval(sprintf("P%dM", self::HYSTERESIS))); 15 | 16 | foreach ($candidate->getEducation() as $education) { 17 | if ($education->getEndDate() < new DateTime() 18 | && $education->getEndDate() > $maxEndDate) { 19 | return true; 20 | } 21 | } 22 | 23 | return false; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Behavioral/Specification/Specification.php: -------------------------------------------------------------------------------- 1 | getEducation() as $education) { 12 | if ($education->getEndDate() > new DateTime()) { 13 | return true; 14 | } 15 | } 16 | 17 | return false; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Behavioral/Specification/WorkExperience.php: -------------------------------------------------------------------------------- 1 | start->diff($this->end); 16 | return ($workedInterval->y * 12) + $workedInterval->m; 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/Behavioral/Specification/WorkExperienceSpecification.php: -------------------------------------------------------------------------------- 1 | getWorkExperience() as $experience) { 16 | $totalMonthsOfExperience += $experience->getWorkedMonths(); 17 | } 18 | 19 | return $totalMonthsOfExperience / 12 >= $this->minYearsOfExperience; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Behavioral/Specification/demo.php: -------------------------------------------------------------------------------- 1 | isSatisfiedBy($candidate)) { 66 | $candidatesToContact[] = $candidate; 67 | } 68 | } 69 | 70 | print_r($candidatesToContact); 71 | -------------------------------------------------------------------------------- /src/Behavioral/State/Angry.php: -------------------------------------------------------------------------------- 1 | say("You too..."); 10 | } 11 | 12 | public function hug(Person $context): void 13 | { 14 | $context->say("Hm..."); 15 | $context->setState(new Neutral()); 16 | } 17 | 18 | public function getName(Person $context, string $name): void 19 | { 20 | $context->say("{$name}. What's your problem?"); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/Behavioral/State/Happy.php: -------------------------------------------------------------------------------- 1 | say("Oh! That wasn't nice"); 10 | $context->setState(new Neutral()); 11 | } 12 | 13 | public function hug(Person $context): void 14 | { 15 | $context->say("Oh! That was nice, thanks"); 16 | } 17 | 18 | public function getName(Person $context, string $name): void 19 | { 20 | $context->say("Oh! Hello dear friend. My name is {$name}"); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Behavioral/State/Mood.php: -------------------------------------------------------------------------------- 1 | say("What the heck do you want?"); 10 | $context->setState(new Angry()); 11 | } 12 | 13 | public function hug(Person $context): void 14 | { 15 | $context->say("Thanks"); 16 | $context->setState(new Happy()); 17 | } 18 | 19 | public function getName(Person $context, string $name): void 20 | { 21 | $context->say("My name is {$name}"); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/Behavioral/State/Person.php: -------------------------------------------------------------------------------- 1 | setState($mood); 13 | $this->name = $name; 14 | } 15 | 16 | public function setState(Mood $mood): void 17 | { 18 | $this->currentMood = $mood; 19 | } 20 | 21 | public function insult(): void 22 | { 23 | $this->currentMood->insult($this); 24 | } 25 | 26 | public function getName(): void 27 | { 28 | $this->currentMood->getName($this, $this->name); 29 | } 30 | 31 | public function hug(): void 32 | { 33 | $this->currentMood->hug($this); 34 | } 35 | 36 | public function say(string $msg): void 37 | { 38 | echo($msg . PHP_EOL); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Behavioral/State/demo.php: -------------------------------------------------------------------------------- 1 | getName(); 9 | $jan->insult(); 10 | $jan->getName(); 11 | $jan->hug(); 12 | $jan->getName(); 13 | $jan->hug(); 14 | $jan->getName(); 15 | -------------------------------------------------------------------------------- /src/Behavioral/Strategy/Context.php: -------------------------------------------------------------------------------- 1 | formatter = match ($outputType) { 12 | "json" => new JSONFormatter(), 13 | "xml" => new XMLFormatter(), 14 | "string" => new StringFormatter(), 15 | default => throw new \InvalidArgumentException("{$outputType} is not supported"), 16 | }; 17 | } 18 | 19 | public function formatData(array $data): string 20 | { 21 | return $this->formatter->format($data); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Behavioral/Strategy/JSONFormatter.php: -------------------------------------------------------------------------------- 1 | addData($data, new SimpleXMLElement('')); 12 | 13 | return $xml->asXML(); 14 | } 15 | 16 | protected function addData(array $data, SimpleXMLElement $xml): SimpleXMLElement 17 | { 18 | foreach ($data as $k => $v) { 19 | is_array($v) 20 | ? $this->addData($v, $xml->addChild($k)) 21 | : $xml->addChild($k, $v); 22 | } 23 | return $xml; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Behavioral/Strategy/demo.php: -------------------------------------------------------------------------------- 1 | "Johny", 9 | "surname" => "Marony", 10 | "company" => "Company Name", 11 | "position" => "Senior Doorkeeper" 12 | ]; 13 | 14 | $jsonContext = new Context('json'); 15 | echo $jsonContext->formatData($exampleData) . PHP_EOL; 16 | 17 | $stringContext = new Context('string'); 18 | echo $stringContext->formatData($exampleData) . PHP_EOL; 19 | 20 | $xmlContext = new Context('xml'); 21 | echo $xmlContext->formatData($exampleData) . PHP_EOL; 22 | -------------------------------------------------------------------------------- /src/Behavioral/TemplateMethod/ActionMovie.php: -------------------------------------------------------------------------------- 1 | budget = 100000; 14 | } 15 | 16 | protected function castActors(): void 17 | { 18 | foreach (array_rand(self::AVAILABLE_ACTORS, self::NUM_ROLES) as $actor) { 19 | $this->cast[] = self::AVAILABLE_ACTORS[$actor]; 20 | } 21 | } 22 | 23 | protected function castDirector(): void 24 | { 25 | $this->director = self::AVAILABLE_DIRECTORS[array_rand(self::AVAILABLE_DIRECTORS)]; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Behavioral/TemplateMethod/ComedyMovie.php: -------------------------------------------------------------------------------- 1 | budget = 500000; 13 | } 14 | 15 | protected function castActors(): void 16 | { 17 | $this->cast[] = 'Adam Sandler'; 18 | $this->cast[] = self::AVAILABLE_ACTORS[array_rand(self::AVAILABLE_ACTORS)]; 19 | } 20 | 21 | protected function castDirector(): void 22 | { 23 | $this->director = self::AVAILABLE_DIRECTORS[array_rand(self::AVAILABLE_DIRECTORS)]; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Behavioral/TemplateMethod/Movie.php: -------------------------------------------------------------------------------- 1 | name = $name; 15 | } 16 | 17 | final public function publish(): void 18 | { 19 | $this->raiseMoney(); 20 | $this->castActors(); 21 | $this->castDirector(); 22 | $this->promote(); 23 | } 24 | 25 | abstract protected function raiseMoney(): void; 26 | 27 | abstract protected function castActors(): void; 28 | 29 | abstract protected function castDirector(): void; 30 | 31 | protected function promote(): void 32 | { 33 | $actors = implode(", ", $this->cast); 34 | echo "New movie '{$this->name}' directed by {$this->director}. Starring {$actors} and budget of \${$this->budget}!" . PHP_EOL; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Behavioral/TemplateMethod/demo.php: -------------------------------------------------------------------------------- 1 | publish(); 9 | 10 | $comedyMovie = new ComedyMovie("Comedy 2"); 11 | $comedyMovie->publish(); 12 | -------------------------------------------------------------------------------- /src/Behavioral/Visitor/SickLeave.php: -------------------------------------------------------------------------------- 1 | start; 14 | } 15 | 16 | public function getEnd(): \DateTime 17 | { 18 | return $this->end; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Behavioral/Visitor/SickLeaveReport.php: -------------------------------------------------------------------------------- 1 | getName()}" . PHP_EOL; 10 | 11 | foreach ($university->getStudents() as $student) { 12 | $msg .= $this->visitStudent($student) . PHP_EOL; 13 | } 14 | 15 | return $msg; 16 | } 17 | 18 | public function visitStudent(Student $student): string 19 | { 20 | $daysMissed = 0; 21 | 22 | foreach ($student->getSickLeaves() as $sickLeave) { 23 | $daysMissed += $sickLeave->getStart()->diff($sickLeave->getEnd())->days + 1; 24 | } 25 | 26 | return "Student: {$student->getName()} missed {$daysMissed} days"; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Behavioral/Visitor/Student.php: -------------------------------------------------------------------------------- 1 | name = $name; 13 | } 14 | 15 | public function addSickLeave(\DateTime $start, \DateTime $end): void 16 | { 17 | $this->sickLeaves[] = new SickLeave($start, $end); 18 | } 19 | 20 | public function getName(): string 21 | { 22 | return $this->name; 23 | } 24 | 25 | public function getSickLeaves(): array 26 | { 27 | return $this->sickLeaves; 28 | } 29 | 30 | public function accept(Visitor $visitor): string 31 | { 32 | return $visitor->visitStudent($this); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Behavioral/Visitor/University.php: -------------------------------------------------------------------------------- 1 | name; 14 | } 15 | 16 | public function getStudents(): array 17 | { 18 | return $this->students; 19 | } 20 | 21 | public function accept(Visitor $visitor): string 22 | { 23 | return $visitor->visitUniversity($this); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Behavioral/Visitor/Visitable.php: -------------------------------------------------------------------------------- 1 | addSickLeave(new \DateTime("2019-10-01"), new \DateTime("2019-10-21")); 9 | $john->addSickLeave(new \DateTime("2019-11-02"), new \DateTime("2019-11-10")); 10 | 11 | $jan = new Student("Jan"); 12 | $jan->addSickLeave(new \DateTime("2019-11-01"), new \DateTime("2019-11-15")); 13 | 14 | $ann = new Student("Ann"); 15 | 16 | $university = new University("Visitor University", [$john, $jan, $ann]); 17 | echo $university->accept(new SickLeaveReport()); -------------------------------------------------------------------------------- /src/Creational/AbstractFactory/DeviceFactory.php: -------------------------------------------------------------------------------- 1 | makeIndoor(); 9 | $outdoorDisplay = $displayFactory->makeOutdoor(); 10 | 11 | $indoorDisplay->testTouch(); 12 | $indoorDisplay->testSensors(); 13 | $outdoorDisplay->testForVandalism(); 14 | $outdoorDisplay->testForWeatherConditions(); 15 | 16 | $iotFactory = new IotFactory(); 17 | $indoorIot = $iotFactory->makeIndoor(); 18 | $outdoorIot = $iotFactory->makeOutdoor(); 19 | 20 | $indoorIot->testTouch(); 21 | $indoorIot->testSensors(); 22 | $outdoorIot->testForVandalism(); 23 | $outdoorIot->testForWeatherConditions(); 24 | -------------------------------------------------------------------------------- /src/Creational/Builder/Device.php: -------------------------------------------------------------------------------- 1 | setHardware() 10 | ->setSoftware() 11 | ->setSLA() 12 | ->getDevice(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Creational/Builder/InteractiveMirror.php: -------------------------------------------------------------------------------- 1 | hardware[] = $hardware; 14 | } 15 | 16 | public function setSoftware(string $software): void 17 | { 18 | $this->software = $software; 19 | } 20 | 21 | public function setSLA(string $SLA): void 22 | { 23 | $this->SLA = $SLA; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Creational/Builder/InteractiveMirrorBuilder.php: -------------------------------------------------------------------------------- 1 | device->attachHardware($component); 18 | } 19 | 20 | return $this; 21 | } 22 | 23 | public function setSoftware(): self 24 | { 25 | $this->device->setSoftware('Mirror software'); 26 | 27 | return $this; 28 | } 29 | 30 | public function setSLA(): self 31 | { 32 | $this->device->setSLA('Mirror SLA V2'); 33 | 34 | return $this; 35 | } 36 | 37 | public function getDevice(): Device 38 | { 39 | return $this->device; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Creational/Builder/demo.php: -------------------------------------------------------------------------------- 1 | buildDevice($mirrorBuilder); 10 | 11 | var_dump($mirror); 12 | -------------------------------------------------------------------------------- /src/Creational/FactoryMethod/AudioBox.php: -------------------------------------------------------------------------------- 1 | file->getFilePath()}' />"; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Creational/FactoryMethod/Box.php: -------------------------------------------------------------------------------- 1 | file = $file; 12 | } 13 | 14 | abstract public function getHtml(): string; 15 | } 16 | -------------------------------------------------------------------------------- /src/Creational/FactoryMethod/BoxFactory.php: -------------------------------------------------------------------------------- 1 | getType()) { 12 | FileItem::TYPE_IMG => new ImgBox($item), 13 | FileItem::TYPE_VIDEO => new VideoBox($item), 14 | FileItem::TYPE_AUDIO => new AudioBox($item), 15 | default => throw new InvalidArgumentException("Wrong file type provided: {$item->getType()}"), 16 | }; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Creational/FactoryMethod/Factory.php: -------------------------------------------------------------------------------- 1 | type; 20 | } 21 | 22 | public function getFilePath(): string 23 | { 24 | return $this->filePath; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Creational/FactoryMethod/ImgBox.php: -------------------------------------------------------------------------------- 1 | file->getFilePath()}' />"; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Creational/FactoryMethod/VideoBox.php: -------------------------------------------------------------------------------- 1 | file->getFilePath()}' />"; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Creational/FactoryMethod/demo.php: -------------------------------------------------------------------------------- 1 | getHtml() . PHP_EOL; 12 | echo BoxFactory::createBox($video)->getHtml() . PHP_EOL; 13 | echo BoxFactory::createBox($audio)->getHtml() . PHP_EOL; 14 | -------------------------------------------------------------------------------- /src/Creational/Prototype/Computer.php: -------------------------------------------------------------------------------- 1 | uuid = $uuid; 17 | 18 | return $this; 19 | } 20 | 21 | public function save(): void 22 | { 23 | echo "Saving device with UID {$this->uuid} to group {$this->group->getName()} in {$this->group->getLocation()}" . PHP_EOL; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Creational/Prototype/Device.php: -------------------------------------------------------------------------------- 1 | name; 16 | } 17 | 18 | public function getLocation(): string 19 | { 20 | return $this->location; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Creational/Prototype/demo.php: -------------------------------------------------------------------------------- 1 | setUuid($uid)->save(); 23 | } 24 | -------------------------------------------------------------------------------- /src/Creational/Singleton/ActiveUser.php: -------------------------------------------------------------------------------- 1 | email = "active@user.com"; 14 | } 15 | 16 | private function __clone() 17 | { 18 | } 19 | 20 | public function setName(string $email): void 21 | { 22 | $this->email = $email; 23 | } 24 | 25 | public function changeEmail(): string 26 | { 27 | return $this->email; 28 | } 29 | 30 | public static function getInstance(): ActiveUser 31 | { 32 | if (!self::$instance) { 33 | self::$instance = new ActiveUser(); 34 | } 35 | return self::$instance; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Structural/Adapter/.env.example: -------------------------------------------------------------------------------- 1 | AWS_ACCESS_KEY_ID="" 2 | AWS_SECRET_ACCESS_KEY="" 3 | AWS_REGION="" 4 | AWS_BUCKET_NAME="" -------------------------------------------------------------------------------- /src/Structural/Adapter/AWSFileStorage.php: -------------------------------------------------------------------------------- 1 | load('.env'); 18 | 19 | $this->bucket = getenv('AWS_BUCKET_NAME') ?? ""; 20 | 21 | $this->client = new S3Client([ 22 | 'version' => 'latest', 23 | 'region' => getenv('AWS_REGION'), 24 | 'credentials' => new Credentials(getenv("AWS_ACCESS_KEY_ID"), getenv("AWS_SECRET_ACCESS_KEY")) 25 | ]); 26 | } 27 | 28 | public function get(string $name): File 29 | { 30 | try { 31 | $file = $this->client->getObject([ 32 | 'Bucket' => $this->bucket, 33 | 'Key' => $name 34 | ]); 35 | 36 | return new File($name, $file['Body']->getContents()); 37 | } catch (\Throwable $e) { 38 | throw new \LogicException($e->getMessage()); 39 | } 40 | } 41 | 42 | public function save(string $path, string $name): void 43 | { 44 | $this->client->putObject([ 45 | 'Bucket' => $this->bucket, 46 | 'Key' => $name, 47 | 'Body' => file_get_contents($path, "r") 48 | ]); 49 | } 50 | 51 | public function delete(string $name): bool 52 | { 53 | try { 54 | $this->client->deleteObject([ 55 | 'Bucket' => $this->bucket, 56 | 'Key' => $name 57 | ]); 58 | } catch (\Throwable $e) { 59 | return false; 60 | } 61 | 62 | return true; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Structural/Adapter/Client.php: -------------------------------------------------------------------------------- 1 | storageProvider = match ($storage) { 15 | 'local' => new LocalFileStorage(), 16 | 'aws' => new AWSFileStorage(), 17 | default => throw new \Exception("Unsupported storage requested $storage"), 18 | }; 19 | } 20 | 21 | public function save(string $filePath, string $name): void 22 | { 23 | $this->storageProvider->save($filePath, $name); 24 | } 25 | 26 | public function get(string $name): File 27 | { 28 | return $this->storageProvider->get($name); 29 | } 30 | 31 | public function delete(string $name) 32 | { 33 | return $this->storageProvider->delete($name); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Structural/Adapter/File.php: -------------------------------------------------------------------------------- 1 | content; 14 | } 15 | 16 | public function getName(): string 17 | { 18 | return $this->name; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Structural/Adapter/FileAdapter.php: -------------------------------------------------------------------------------- 1 | get($_POST['fileName']); 18 | 19 | header("Content-Type: application/octet-stream"); 20 | header("Content-Transfer-Encoding: Binary"); 21 | header("Content-disposition: attachment; filename=\"{$file->getName()}\""); 22 | 23 | echo $file->getContent(); 24 | 25 | } catch (\Exception $e) { 26 | $msg = $e->getMessage(); 27 | } 28 | 29 | } elseif (strtolower($_POST['action']) === 'delete') { 30 | try { 31 | $client->delete($_POST['fileName']); 32 | $msg = "File '{$_POST['fileName']}' deleted from storage '{$_POST['storage']}'"; 33 | } catch (\Exception $e) { 34 | $msg = $e->getMessage(); 35 | } 36 | } 37 | } 38 | 39 | if (sizeof($_FILES) && array_key_exists("storage", $_POST)) { 40 | $client = new Client($_POST['storage']); 41 | 42 | try { 43 | $fileName = $_FILES['file']["name"]; 44 | $client->save($_FILES['file']["tmp_name"], $fileName); 45 | 46 | $msg = "File '{$_FILES['file']["name"]}' uploaded to storage '{$_POST['storage']}'"; 47 | } catch (\Exception $e) { 48 | $msg = $e->getMessage(); 49 | } 50 | } 51 | ?> 52 | 53 | 54 | 55 | 56 | 57 | Adapter Demo 58 | 59 | 61 | 64 | 67 | 70 | 71 | 72 | 73 |
74 |
75 | 76 |
77 |
78 |
79 |
82 |
Upload your file here
83 |
84 | 89 | 90 |
91 | 92 |
93 |
94 | 96 | 97 |
98 |
99 | 100 | 101 |
102 |
103 | 104 | 105 |
106 |
107 |
108 | 109 |
110 |
111 | 112 |
113 | 114 |
115 | 116 | 122 | Enter filename, choose its storage and action 123 |
124 | 125 |
126 |
127 | 129 | 130 |
131 |
132 | 133 | 134 |
135 |
136 | 137 | 138 |
139 |
140 |
141 | 142 | 146 |
147 | 148 |
149 |
150 | 151 | 152 |
153 | 154 | 155 | 158 | 159 |
160 | 161 | 162 | 168 | 169 | -------------------------------------------------------------------------------- /src/Structural/Adapter/server.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | php -S localhost:8000 4 | -------------------------------------------------------------------------------- /src/Structural/Adapter/storage/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jkapuscik2/design-patterns-php/824df7fd86743fa6aaae0cae9ed99cfa1318409a/src/Structural/Adapter/storage/.gitkeep -------------------------------------------------------------------------------- /src/Structural/Bridge/Blurred.php: -------------------------------------------------------------------------------- 1 | content->getHtml(); 10 | $css = $this->content->getCss(); 11 | 12 | return << 16 | $css 17 | .content { 18 | filter: blur(5px); 19 | -webkit-filter: blur(5px); 20 | } 21 | 22 | CONTENT; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Structural/Bridge/Content.php: -------------------------------------------------------------------------------- 1 | filePath' />"; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Structural/Bridge/Standard.php: -------------------------------------------------------------------------------- 1 | content->getHtml(); 10 | $css = $this->content->getCss(); 11 | 12 | return << 16 | $css 17 | 18 | CONTENT; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/Structural/Bridge/Video.php: -------------------------------------------------------------------------------- 1 | filePath' autoplay muted loop>"; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Structural/Bridge/demo.php: -------------------------------------------------------------------------------- 1 | render() . PHP_EOL); 17 | echo($blurredDisplayVid->render() . PHP_EOL); 18 | 19 | echo($displayImg->render() . PHP_EOL); 20 | echo($blurredDisplayImg->render() . PHP_EOL); 21 | -------------------------------------------------------------------------------- /src/Structural/Composite/Budgeted.php: -------------------------------------------------------------------------------- 1 | dependencies = new SplObjectStorage(); 14 | } 15 | 16 | public function calculateBudget(): int 17 | { 18 | $total = 0; 19 | 20 | foreach ($this->getDependent() as $dependent) { 21 | $total += $dependent->calculateBudget(); 22 | } 23 | 24 | return $total; 25 | } 26 | 27 | public function getDependent(): SplObjectStorage 28 | { 29 | return $this->dependencies; 30 | } 31 | 32 | public function addDependent(Budgeted $item): void 33 | { 34 | $this->dependencies->attach($item); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Structural/Composite/Employee.php: -------------------------------------------------------------------------------- 1 | salary; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Structural/Composite/demo.php: -------------------------------------------------------------------------------- 1 | addDependent($emmy); 13 | $accounting->addDependent($emma); 14 | 15 | $it = new Department("IT"); 16 | $sara = new Employee("Sara", 10000); 17 | $john = new Employee("John", 5000); 18 | $it->addDependent($sara); 19 | $it->addDependent($john); 20 | 21 | $devops = new Department("Devops"); 22 | $johny = new Employee("Johny", 15000); 23 | $devops->addDependent($johny); 24 | 25 | $company->addDependent($accounting); 26 | $company->addDependent($it); 27 | 28 | echo("Total company salaries: \${$company->calculateBudget()}" . PHP_EOL); 29 | -------------------------------------------------------------------------------- /src/Structural/Decorator/Product.php: -------------------------------------------------------------------------------- 1 | product = $product; 12 | } 13 | 14 | abstract public function getName(): string; 15 | 16 | abstract public function getPrice(): int; 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/Structural/Decorator/Shirt.php: -------------------------------------------------------------------------------- 1 | name}"; 16 | } 17 | 18 | public function getPrice(): int 19 | { 20 | return round($this->price * self::TAX_RATE); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Structural/Decorator/SummerSale.php: -------------------------------------------------------------------------------- 1 | product->getName()} ONLY {$this->getPrice()} EUR"; 12 | } 13 | 14 | public function getPrice(): int 15 | { 16 | return round($this->product->getPrice() * self::DISCOUNT_FACTOR); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/Structural/Decorator/TV.php: -------------------------------------------------------------------------------- 1 | name"; 16 | } 17 | 18 | public function getPrice(): int 19 | { 20 | return round($this->price * self::TAX_RATE); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Structural/Decorator/WinterSale.php: -------------------------------------------------------------------------------- 1 | product->getName()} ONLY {$this->getPrice()} EUR"; 12 | } 13 | 14 | public function getPrice(): int 15 | { 16 | return round($this->product->getPrice() * self::DISCOUNT_FACTOR); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/Structural/Decorator/demo.php: -------------------------------------------------------------------------------- 1 | getName() . PHP_EOL); 11 | echo($tv->getName()) . PHP_EOL; 12 | 13 | $winterShirt = new WinterSale($shirt); 14 | $winterTv = new WinterSale($tv); 15 | 16 | echo($winterShirt->getName() . PHP_EOL); 17 | echo($winterTv->getName() . PHP_EOL); 18 | 19 | $summerShirt = new SummerSale($shirt); 20 | $summerTv = new SummerSale($tv); 21 | 22 | echo($summerShirt->getName() . PHP_EOL); 23 | echo($summerTv->getName() . PHP_EOL); 24 | -------------------------------------------------------------------------------- /src/Structural/DependencyInjection/Storage.php: -------------------------------------------------------------------------------- 1 | 3 && mb_strlen($password) > 3) { 14 | return true; 15 | } else { 16 | return false; 17 | } 18 | } 19 | 20 | public function register(string $email, string $password): bool 21 | { 22 | if ($this->validate($email, $password) 23 | && $this->userStorage->save($email, $password)) { 24 | 25 | return true; 26 | } else { 27 | return false; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Structural/DependencyInjection/UserStorage.php: -------------------------------------------------------------------------------- 1 | connectDb(); 15 | echo "Inserting new user record with email: {$email} and password {$password}"; 16 | 17 | return true; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Structural/DependencyInjection/UserTest.php: -------------------------------------------------------------------------------- 1 | getMockBuilder(UserStorage::class) 12 | ->disableOriginalConstructor() 13 | ->onlyMethods(["save"]) 14 | ->getMock(); 15 | $userStorage->expects($this->once())->method("save")->willReturn(true); 16 | 17 | $user = new User($userStorage); 18 | $testEmail = "aaaaa@wp.pl"; 19 | $testPassword = "123456"; 20 | 21 | $this->assertTrue($user->register($testEmail, $testPassword)); 22 | } 23 | 24 | public function testRegisterFail() 25 | { 26 | $userStorage = $this->getMockBuilder(UserStorage::class) 27 | ->disableOriginalConstructor() 28 | ->onlyMethods(["save"]) 29 | ->getMock(); 30 | $userStorage->expects($this->once())->method("save")->willReturn(false); 31 | 32 | $user = new User($userStorage); 33 | $testEmail = "aaaaa@wp.pl"; 34 | $testPassword = "123456"; 35 | 36 | $this->assertFalse($user->register($testEmail, $testPassword)); 37 | } 38 | 39 | public function testRegisterValidationFail() 40 | { 41 | $userStorage = $this->getMockBuilder(UserStorage::class) 42 | ->disableOriginalConstructor() 43 | ->onlyMethods(["save"]) 44 | ->getMock(); 45 | $userStorage->expects($this->never())->method("save"); 46 | 47 | $user = new User($userStorage); 48 | $wrongEmail = "aa"; 49 | $wrongPassword = "12"; 50 | 51 | $this->assertFalse($user->register($wrongEmail, $wrongPassword)); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/Structural/Facade/Image.php: -------------------------------------------------------------------------------- 1 | imagick = new Imagick(); 15 | } 16 | 17 | public function thumbnail(string $filePath, int $width, int $height): true 18 | { 19 | $this->imagick->readImage($filePath); 20 | $this->imagick->setbackgroundcolor('rgb(0, 0, 0)'); 21 | $this->imagick->thumbnailImage($width, $height, true, true); 22 | 23 | $fileInfo = new SplFileInfo($filePath); 24 | $thumbPath = $fileInfo->getBasename('.' . $fileInfo->getExtension()) . '_thumb' . "." . $fileInfo->getExtension(); 25 | 26 | if (file_put_contents($thumbPath, $this->imagick)) { 27 | return true; 28 | } else { 29 | throw new \RuntimeException("Could not create thumbnail."); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Structural/Facade/demo.php: -------------------------------------------------------------------------------- 1 | thumbnail(__DIR__ . "/../../../demo.jpg", 100, 100); 9 | -------------------------------------------------------------------------------- /src/Structural/FluentInterface/QueryBuilder.php: -------------------------------------------------------------------------------- 1 | query .= sprintf("SELECT %s ", sizeof($fields) ? implode(", ", $fields) : "*"); 12 | 13 | return $this; 14 | } 15 | 16 | public function from(string $tableName): QueryBuilder 17 | { 18 | $this->query .= " FROM {$tableName} "; 19 | 20 | return $this; 21 | } 22 | 23 | public function where(array $conditions): QueryBuilder 24 | { 25 | $this->query .= sprintf("WHERE %s ", implode(" AND ", $conditions)); 26 | 27 | return $this; 28 | } 29 | 30 | public function offset(int $offset): QueryBuilder 31 | { 32 | $this->query .= "OFFSET {$offset} "; 33 | 34 | return $this; 35 | } 36 | 37 | public function limit(int $limit): QueryBuilder 38 | { 39 | $this->query .= "LIMIT {$limit} "; 40 | 41 | return $this; 42 | } 43 | 44 | public function orderBy(string $orderRule): QueryBuilder 45 | { 46 | $this->query .= "ORDER BY {$orderRule} "; 47 | 48 | return $this; 49 | } 50 | 51 | public function getQuery(): string 52 | { 53 | return $this->query; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/Structural/FluentInterface/demo.php: -------------------------------------------------------------------------------- 1 | select(["name", "surname"]) 9 | ->from("users") 10 | ->where(["name = 'John'", "city = 'Warsaw'"]) 11 | ->orderBy("date ASC") 12 | ->limit(10) 13 | ->getQuery(); 14 | -------------------------------------------------------------------------------- /src/Structural/Flyweight/Device.php: -------------------------------------------------------------------------------- 1 | uuid} is active" . PHP_EOL; 18 | echo $this->type->reportType() . PHP_EOL; 19 | echo "Calling it on ip {$this->ip}" . PHP_EOL; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Structural/Flyweight/DeviceStorage.php: -------------------------------------------------------------------------------- 1 | deviceFactory = new DeviceTypeFactory(); 16 | } 17 | 18 | public function addDevice( 19 | string $uuid, 20 | string $location, 21 | string $resolution, 22 | string $producer, 23 | string $operatingSystem, 24 | string $ip 25 | ): void 26 | { 27 | $type = $this->deviceFactory->getType( 28 | $location, 29 | $resolution, 30 | $producer, 31 | $operatingSystem 32 | ); 33 | 34 | $this->devices[] = new Device($uuid, $ip, $type); 35 | } 36 | 37 | public function checkDevicesHealth(): void 38 | { 39 | foreach ($this->devices as $device) { 40 | $device->ping(); 41 | } 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/Structural/Flyweight/DeviceType.php: -------------------------------------------------------------------------------- 1 | location} with resolution {$this->resolution} crated by {$this->producer} and running {$this->operatingSystem}"; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Structural/Flyweight/DeviceTypeFactory.php: -------------------------------------------------------------------------------- 1 | getKey( 17 | $location, 18 | $resolution, 19 | $producer, 20 | $operatingSystem 21 | ); 22 | 23 | // if (!array_key_exists($key, $this->deviceTypes)) { 24 | $this->deviceTypes[$key] = new DeviceType( 25 | $location, 26 | $resolution, 27 | $producer, 28 | $operatingSystem 29 | ); 30 | // } 31 | 32 | return $this->deviceTypes[$key]; 33 | } 34 | 35 | protected function getKey( 36 | string $location, 37 | string $resolution, 38 | string $producer, 39 | string $operatingSystem 40 | ): string 41 | { 42 | return md5(implode("_", func_get_args())); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Structural/Flyweight/Generator.php: -------------------------------------------------------------------------------- 1 | numItems = $numItems; 20 | $this->fileName = $fileName; 21 | } 22 | 23 | protected function createHeader(): void 24 | { 25 | fputcsv($this->file, self::COLUMNS); 26 | } 27 | 28 | protected function generateRandomString(int $length): string 29 | { 30 | return substr(str_shuffle(str_repeat($x = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', ceil($length / strlen($x)))), 1, $length); 31 | } 32 | 33 | protected function getRand(array $arr): string 34 | { 35 | $key = array_rand($arr); 36 | 37 | return $arr[$key]; 38 | } 39 | 40 | protected function getRandIp(): string 41 | { 42 | return mt_rand(0, 255) . "." . mt_rand(0, 255) . "." . mt_rand(0, 255) . "." . mt_rand(0, 255); 43 | } 44 | 45 | protected function generateData(): void 46 | { 47 | for ($idx = 0; $idx < $this->numItems; $idx++) { 48 | fputcsv($this->file, [ 49 | $idx + 1, 50 | $this->generateRandomString(rand(5, 10)), 51 | $this->getRand(self::LOCATIONS), 52 | $this->getRand(self::RESOLUTIONS), 53 | $this->getRand(self::PRODUCERS), 54 | $this->getRand(self::OPERATING_SYSTEMS), 55 | $this->getRandIp() 56 | ]); 57 | } 58 | } 59 | 60 | public function create(): void 61 | { 62 | $this->file = fopen($this->fileName, 'w'); 63 | $this->createHeader(); 64 | $this->generateData(); 65 | fclose($this->file); 66 | } 67 | } 68 | 69 | -------------------------------------------------------------------------------- /src/Structural/Flyweight/demo.php: -------------------------------------------------------------------------------- 1 | create(); 9 | 10 | $file = fopen('demo.csv', 'r'); 11 | 12 | $devicesDB = new DeviceStorage(); 13 | 14 | for ($i = 0; $row = fgetcsv($file); ++$i) { 15 | // Omitting file headers 16 | if ($i) { 17 | $devicesDB->addDevice( 18 | $row[1], 19 | $row[2], 20 | $row[3], 21 | $row[4], 22 | $row[5], 23 | $row[6] 24 | ); 25 | } 26 | } 27 | 28 | fclose($file); 29 | 30 | $devicesDB->checkDevicesHealth(); 31 | 32 | // 3.4 MB RAM USED 33 | // 22.92 MB RAM USED 34 | 35 | // 2.21 MB RAM USED 36 | // 10.91 MB RAM USED 37 | 38 | echo round(memory_get_usage() / 1024 / 1024, 2) . " MB RAM USED"; 39 | -------------------------------------------------------------------------------- /src/Structural/Proxy/AuthFile.php: -------------------------------------------------------------------------------- 1 | loggedIn()) { 20 | $this->file->add($name, $path); 21 | } 22 | } 23 | 24 | public function get(string $name): void 25 | { 26 | if ($this->loggedIn()) { 27 | $this->file->get($name); 28 | } 29 | } 30 | 31 | public function remove(string $name): void 32 | { 33 | if ($this->loggedIn()) { 34 | $this->file->remove($name); 35 | } 36 | } 37 | 38 | private function loggedIn(): bool 39 | { 40 | if (isset($_SESSION["username"]) && in_array($_SESSION["username"], self::ALLOWED_USERS)) { 41 | echo "User can perform action" . PHP_EOL; 42 | 43 | return true; 44 | } else { 45 | echo "User can not perform action" . PHP_EOL; 46 | 47 | return false; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Structural/Proxy/File.php: -------------------------------------------------------------------------------- 1 | add("test-file.png", "/home/ubuntu"); 13 | $fileAuth->remove("test-file.png"); 14 | $fileAuth->get("test-file.png"); 15 | 16 | $auth = new User(); 17 | $auth->login("Jan"); 18 | 19 | $fileAuth->add("test-file.png", "/home/ubuntu"); 20 | $fileAuth->remove("test-file.png"); 21 | $fileAuth->get("test-file.png"); 22 | 23 | $auth->logOut(); 24 | $auth->login("BB"); 25 | 26 | $fileAuth->add("test-file.png", "/home/ubuntu"); 27 | $fileAuth->remove("test-file.png"); 28 | $fileAuth->get("test-file.png"); 29 | session_destroy(); 30 | --------------------------------------------------------------------------------