├── commands.sqlite ├── tests ├── .gitignore ├── ProxyPatternTest.php ├── AdapterPatternTest.php ├── BridgeTest.php ├── DecoratorPatternTest.php ├── MailerDependencyInjectionTest.php ├── CompositePatternTest.php ├── IteratorPatternTest.php ├── AcmePrototypeTest.php ├── StaticFactoryTest.php ├── RegisteryPatternTest.php ├── StorageDataMapperTest.php ├── FactoryMethod2Test.php ├── ObserverPatternTest.php ├── WorkerPoolTest.php ├── FacadeTest.php ├── AdapaterPatternExample2Test.php ├── ChainOfResponsibilityTest.php ├── FactoryMethodTest.php ├── CommandTest.php ├── MealBuilderTest.php ├── DatabaseBuilderTest.php └── AbstractTvFactoryTest.php ├── .gitignore ├── app ├── Controller │ ├── factory.txt │ ├── BehavioralController.php │ ├── StructuralController.php │ └── CreationalController.php ├── Patterns │ ├── Structural │ │ ├── ProxyPattern │ │ │ └── FileReader │ │ │ │ ├── data.json │ │ │ │ ├── README.md │ │ │ │ ├── illustration.png │ │ │ │ ├── FileReader.php │ │ │ │ ├── Application.php │ │ │ │ ├── JsonFileReader.php │ │ │ │ └── JsonFileReaderProxy.php │ │ ├── CompositePattern │ │ │ └── Form │ │ │ │ ├── README.md │ │ │ │ ├── illustration.png │ │ │ │ ├── Fieldset.php │ │ │ │ ├── Form.php │ │ │ │ ├── InputField.php │ │ │ │ ├── AbstractFormField.php │ │ │ │ ├── FieldComposite.php │ │ │ │ └── Application.php │ │ ├── AdapterPattern │ │ │ ├── Human │ │ │ │ ├── README.md │ │ │ │ ├── illustration.png │ │ │ │ ├── Human.php │ │ │ │ ├── Men.php │ │ │ │ ├── Kids.php │ │ │ │ ├── Application.php │ │ │ │ └── KidsAdapter.php │ │ │ └── OperatingSystems │ │ │ │ ├── README.md │ │ │ │ ├── illustration.png │ │ │ │ ├── OperatingSystem.php │ │ │ │ ├── LinuxOperatingSystem.php │ │ │ │ ├── Operator.php │ │ │ │ ├── Application.php │ │ │ │ ├── IOSOperatingSystem.php │ │ │ │ └── LinuxOperatingSystemAdapter.php │ │ ├── BridgePattern │ │ │ └── FlightApi │ │ │ │ ├── README.md │ │ │ │ ├── illustration.png │ │ │ │ ├── FlightRenderer.php │ │ │ │ ├── AbstractFlightTicket.php │ │ │ │ ├── SabreTicket.php │ │ │ │ ├── TravelportTicket.php │ │ │ │ ├── Application.php │ │ │ │ ├── SabreFlightRenderer.php │ │ │ │ └── TravelportFlightRenderer.php │ │ ├── Facade │ │ │ └── Quickbooks │ │ │ │ ├── README.md │ │ │ │ ├── illustration.png │ │ │ │ ├── Quickbooks.php │ │ │ │ ├── Exceptions │ │ │ │ └── QuickBooksItemNotFoundException.php │ │ │ │ ├── Item.php │ │ │ │ ├── Application.php │ │ │ │ ├── QuickbooksItems.php │ │ │ │ └── QuickbooksFacade.php │ │ ├── DecoratorPattern │ │ │ └── ActiveRecord │ │ │ │ ├── README.md │ │ │ │ ├── illustration.png │ │ │ │ ├── ActiveRecord.php │ │ │ │ ├── User.php │ │ │ │ ├── Application.php │ │ │ │ └── AdminFilter.php │ │ ├── DependencyInjectionPattern │ │ │ └── Mailer │ │ │ │ ├── README.md │ │ │ │ ├── illustration.png │ │ │ │ ├── Mailer.php │ │ │ │ ├── Application.php │ │ │ │ ├── Drivers │ │ │ │ └── Sendmail.php │ │ │ │ └── MailManager.php │ │ ├── DataMapperPattern │ │ │ ├── StorageDataMapper.php │ │ │ ├── UserMapper.php │ │ │ └── User.php │ │ └── RegisteryPattern │ │ │ └── Exam │ │ │ ├── Application.php │ │ │ └── ExamRegistery.php │ ├── Behavioral │ │ ├── Command │ │ │ └── ApiScrapper │ │ │ │ ├── .gitignore │ │ │ │ ├── README.md │ │ │ │ ├── illustration.png │ │ │ │ ├── HttpRequest.php │ │ │ │ ├── Command.php │ │ │ │ ├── Application.php │ │ │ │ ├── AbstractApiScrapper.php │ │ │ │ ├── KlookApiScrapper.php │ │ │ │ ├── JsonApiManager.php │ │ │ │ └── Queue.php │ │ ├── Iterator │ │ │ └── HotelSuppliers │ │ │ │ ├── README.md │ │ │ │ ├── illustration.png │ │ │ │ ├── DTWSupplier.php │ │ │ │ ├── HTOSupplier.php │ │ │ │ ├── Application.php │ │ │ │ ├── DTWSupplierIterator.php │ │ │ │ └── HTOSupplierIterator.php │ │ ├── Observer │ │ │ └── NewUserSignedup │ │ │ │ ├── README.md │ │ │ │ ├── illustration.png │ │ │ │ ├── ConfirmWhatsapp.php │ │ │ │ ├── SendConfirmationEmail.php │ │ │ │ ├── User.php │ │ │ │ ├── Application.php │ │ │ │ └── NewUserSignedup.php │ │ └── ChainOfResponsibility │ │ │ └── HandleHttpRequests │ │ │ ├── README.md │ │ │ ├── illustration.png │ │ │ ├── Middleware.php │ │ │ ├── GuestMiddleware.php │ │ │ ├── AdminMiddleware.php │ │ │ ├── AuthMiddleware.php │ │ │ ├── Request.php │ │ │ ├── AbstractMiddleware.php │ │ │ └── Application.php │ └── Creational │ │ ├── FactoryMethod │ │ ├── Logger │ │ │ ├── .gitignore │ │ │ ├── README.md │ │ │ ├── illustration.png │ │ │ ├── Logger.php │ │ │ ├── LoggerFactory.php │ │ │ ├── StdLogger.php │ │ │ ├── StdLoggerFactory.php │ │ │ ├── FileLogger.php │ │ │ ├── FileLoggerFactory.php │ │ │ └── Application.php │ │ └── CarManufacturer │ │ │ ├── README.md │ │ │ ├── illustration.png │ │ │ ├── VehicleInterface.php │ │ │ ├── FactoryMethod.php │ │ │ ├── GermanFactory.php │ │ │ ├── ItalianFactory.php │ │ │ ├── Alto.php │ │ │ ├── Ferrari.php │ │ │ ├── Mehran.php │ │ │ ├── Suzki.php │ │ │ └── Application.php │ │ ├── Pool │ │ └── Worker │ │ │ ├── README.md │ │ │ ├── illustration.png │ │ │ ├── StringReverseWorker.php │ │ │ └── WorkerPool.php │ │ ├── Builder │ │ ├── Database │ │ │ ├── README.md │ │ │ ├── illustration.png │ │ │ ├── SqlQueryBuilder.php │ │ │ ├── PostgresQueryBuilder.php │ │ │ ├── Application.php │ │ │ ├── DatabaseQueryBuilder.php │ │ │ ├── DB.php │ │ │ └── MysqlQueryBuilder.php │ │ └── Resturant │ │ │ ├── README.md │ │ │ ├── illustration.png │ │ │ ├── Packing.php │ │ │ ├── Item.php │ │ │ ├── Bottle.php │ │ │ ├── Wrapper.php │ │ │ ├── Burger.php │ │ │ ├── ColdDrink.php │ │ │ ├── Coke.php │ │ │ ├── Pepsi.php │ │ │ ├── ChickenBurger.php │ │ │ ├── VegitableBurger.php │ │ │ ├── Application.php │ │ │ ├── MealBuilder.php │ │ │ └── Meal.php │ │ ├── Prototype │ │ └── AcmePrototype │ │ │ ├── README.md │ │ │ ├── illustration.png │ │ │ ├── Management.php │ │ │ ├── Engineering.php │ │ │ ├── Marketing.php │ │ │ ├── IAcmePrototype.php │ │ │ └── Application.php │ │ ├── StaticFactory │ │ └── Suppliers │ │ │ ├── README.md │ │ │ ├── illustration.png │ │ │ ├── Supplier.php │ │ │ ├── Application.php │ │ │ ├── SabreSupplier.php │ │ │ ├── TravelportSupplier.php │ │ │ └── FlightSupplierFactory.php │ │ └── AbstractPattern │ │ └── TvManufacturer │ │ ├── README.md │ │ ├── illustration.png │ │ ├── SonyLcdTv.php │ │ ├── HuwaiLedTv.php │ │ ├── SonyPlasmaTv.php │ │ ├── HuwaiSmartTv.php │ │ ├── Television.php │ │ ├── Application.php │ │ ├── TvFactory.php │ │ ├── SonyTvFactory.php │ │ ├── HuwaiTvFactory.php │ │ └── TvHelper.php └── Commands │ └── CreateTestFileCommand.php ├── public └── index.php ├── stubs └── Test.stub ├── phpunit.xml ├── bootstraps ├── console_autoload.php ├── autoload.php └── routes.php ├── composer.json └── README.md /commands.sqlite: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/.gitignore: -------------------------------------------------------------------------------- 1 | *.txt 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | /composer.lock -------------------------------------------------------------------------------- /app/Controller/factory.txt: -------------------------------------------------------------------------------- 1 | This text to be written on a file -------------------------------------------------------------------------------- /app/Patterns/Structural/ProxyPattern/FileReader/data.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /app/Patterns/Behavioral/Command/ApiScrapper/.gitignore: -------------------------------------------------------------------------------- 1 | *.sqlite 2 | -------------------------------------------------------------------------------- /app/Patterns/Creational/FactoryMethod/Logger/.gitignore: -------------------------------------------------------------------------------- 1 | *.txt 2 | -------------------------------------------------------------------------------- /public/index.php: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | ./tests 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/Patterns/Behavioral/ChainOfResponsibility/HandleHttpRequests/Middleware.php: -------------------------------------------------------------------------------- 1 | handle(); 11 | } -------------------------------------------------------------------------------- /app/Patterns/Creational/Builder/Database/SqlQueryBuilder.php: -------------------------------------------------------------------------------- 1 | Sending verification code to: ' . $subject->getUser()->getPhoneNo(); 8 | } 9 | } -------------------------------------------------------------------------------- /app/Patterns/Structural/CompositePattern/Form/Fieldset.php: -------------------------------------------------------------------------------- 1 | {$this->title}\n{$output}"; 9 | } 10 | } -------------------------------------------------------------------------------- /app/Patterns/Behavioral/Observer/NewUserSignedup/SendConfirmationEmail.php: -------------------------------------------------------------------------------- 1 | Sending confirmation email to: ' . $subject->getUser()->getEmail(); 8 | } 9 | } -------------------------------------------------------------------------------- /app/Patterns/Creational/StaticFactory/Suppliers/Supplier.php: -------------------------------------------------------------------------------- 1 | flightRenderer = $renderer; 9 | } 10 | 11 | public abstract function view(): string; 12 | } -------------------------------------------------------------------------------- /app/Patterns/Behavioral/ChainOfResponsibility/HandleHttpRequests/GuestMiddleware.php: -------------------------------------------------------------------------------- 1 | user) { 7 | return false; 8 | } 9 | return parent::handle($request); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /app/Patterns/Creational/AbstractPattern/TvManufacturer/SonyLcdTv.php: -------------------------------------------------------------------------------- 1 | role !== 'admin') { 7 | return false; 8 | } 9 | return parent::handle($request); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /app/Patterns/Behavioral/ChainOfResponsibility/HandleHttpRequests/AuthMiddleware.php: -------------------------------------------------------------------------------- 1 | user !== 'basheer') { 7 | return false; 8 | } 9 | return parent::handle($request); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /app/Patterns/Behavioral/Command/ApiScrapper/Application.php: -------------------------------------------------------------------------------- 1 | isEmpty()) { 9 | $http = new JsonApiManager; 10 | $queue->add(new KlookApiScrapper($http)); 11 | } 12 | 13 | $queue->work(); 14 | } 15 | } -------------------------------------------------------------------------------- /app/Patterns/Structural/AdapterPattern/Human/Application.php: -------------------------------------------------------------------------------- 1 | walk() . '
'; 9 | echo $men->speak() . '
'; 10 | 11 | $kids = new KidsAdapter; 12 | echo $kids->walk(); 13 | echo $kids->speak() . '
'; 14 | } 15 | } -------------------------------------------------------------------------------- /app/Patterns/Structural/ProxyPattern/FileReader/Application.php: -------------------------------------------------------------------------------- 1 | isReadable(); 9 | echo '
File Size is: ' . $file->getFileSize() . ' KB'; 10 | echo '
Is File Writable: ' . $file->isWritable(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /app/Patterns/Creational/Builder/Resturant/Coke.php: -------------------------------------------------------------------------------- 1 | 'Basheer', 'role' => 'admin'], 7 | ['name' => 'Asim', 'role' => 'hr'], 8 | ['name' => 'Ali', 'role' => 'software engineer'], 9 | ]; 10 | 11 | public function all(): array 12 | { 13 | return $this->_users; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/Patterns/Behavioral/Iterator/HotelSuppliers/DTWSupplier.php: -------------------------------------------------------------------------------- 1 | 1, 'name' => 'Sri Sutra Hotel Kuala Lumpur'], 7 | ['id' => 2, 'name' => 'Hotel Inn Kuala Lumpur'], 8 | ['id' => 3, 'name' => 'Moven Pick Hotel Kuala Lumpur'] 9 | ]; 10 | 11 | public function getHotels() 12 | { 13 | return $this->_hotels; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/Patterns/Behavioral/Iterator/HotelSuppliers/HTOSupplier.php: -------------------------------------------------------------------------------- 1 | 1, 'title' => 'Avari tower hotel Kuala Lumpur'], 7 | ['id' => 2, 'title' => 'Mehran hotel Kuala Lumpur'], 8 | ['id' => 3, 'title' => 'Foo Hotel Kuala Lumpur'] 9 | ]; 10 | 11 | public function getHotels() 12 | { 13 | return $this->_hotels; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/Patterns/Structural/BridgePattern/FlightApi/SabreTicket.php: -------------------------------------------------------------------------------- 1 | flightRenderer->renderID(1)} 9 | {$this->flightRenderer->renderTitle('TICKETING WITH SABRE')} 10 | {$this->flightRenderer->renderOrigin('KUL')} - {$this->flightRenderer->renderDestination('LHR')}"; 11 | } 12 | } -------------------------------------------------------------------------------- /app/Patterns/Creational/StaticFactory/Suppliers/Application.php: -------------------------------------------------------------------------------- 1 | request('My booking was cancelled without prior notification') . "

"; 9 | 10 | $supplier = FlightSupplierFactory::get(2); 11 | echo $supplier->request('Please book a ticket for me'); 12 | } 13 | } -------------------------------------------------------------------------------- /app/Patterns/Behavioral/Iterator/HotelSuppliers/Application.php: -------------------------------------------------------------------------------- 1 | append(new DTWSupplierIterator(new DTWSupplier)); 9 | $iterator->append(new HTOSupplierIterator(new HTOSupplier)); 10 | 11 | foreach ($iterator as $value) { 12 | echo '
value: '.  $value;
13 |     }
14 |   }
15 | }
16 | 


--------------------------------------------------------------------------------
/app/Patterns/Creational/StaticFactory/Suppliers/SabreSupplier.php:
--------------------------------------------------------------------------------
 1 | flightRenderer->renderID(1)} 
 8 |     {$this->flightRenderer->renderTitle('TICKETING WITH TRAVELPORT')}
 9 |     {$this->flightRenderer->renderOrigin('KUL')} - {$this->flightRenderer->renderDestination('LBU')}";
10 |   }
11 | }


--------------------------------------------------------------------------------
/app/Patterns/Creational/Builder/Resturant/ChickenBurger.php:
--------------------------------------------------------------------------------
 1 | kids = new Kids;
10 |     }
11 | 
12 |     public function speak() : string {
13 |       return $this->kids->SmileOrWeep();
14 |     }
15 | 
16 |     public function walk() : string {
17 |       return $this->kids->move();
18 |     }
19 | }
20 | 


--------------------------------------------------------------------------------
/app/Patterns/Structural/DataMapperPattern/StorageDataMapper.php:
--------------------------------------------------------------------------------
 1 | data = $data;
13 |   }
14 | 
15 |   public function find(int $id)
16 |   {
17 |     if(isset($this->data[$id])) {
18 |       return $this->data[$id];
19 |     }
20 |     return null;
21 |   }
22 | }


--------------------------------------------------------------------------------
/app/Patterns/Structural/DependencyInjectionPattern/Mailer/Application.php:
--------------------------------------------------------------------------------
 1 | to(['foo@foo.com']);
12 |     $manager->cc(['biz@biz.com']);
13 |     echo $manager->send();
14 |   }
15 | }


--------------------------------------------------------------------------------
/app/Patterns/Creational/AbstractPattern/TvManufacturer/HuwaiSmartTv.php:
--------------------------------------------------------------------------------
 1 | url = $url;
10 |     parent::__construct($name, $title);
11 |   }
12 | 
13 |   public function render(): string
14 |   {
15 |     $output = parent::render();
16 |     return "
url}\">

{$this->title}

{$output}
"; 17 | } 18 | } -------------------------------------------------------------------------------- /app/Patterns/Structural/BridgePattern/FlightApi/Application.php: -------------------------------------------------------------------------------- 1 | view(); 10 | 11 | $renderer = new TravelportFlightRenderer; 12 | $travelportTicket = new TravelportTicket($renderer); 13 | echo $travelportTicket->view(); 14 | } 15 | } -------------------------------------------------------------------------------- /app/Patterns/Behavioral/ChainOfResponsibility/HandleHttpRequests/Request.php: -------------------------------------------------------------------------------- 1 | request = json_decode(\json_encode($request)); 10 | } 11 | 12 | 13 | public function __get($key) 14 | { 15 | if(isset($this->request->{$key})) { 16 | return $this->request->{$key}; 17 | } 18 | return null; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/Patterns/Creational/FactoryMethod/Logger/FileLogger.php: -------------------------------------------------------------------------------- 1 | filePath = $filePath; 10 | } 11 | /** 12 | * log to be printed on the screen 13 | * 14 | * @param null 15 | * @return void 16 | */ 17 | public function log(string $message) 18 | { 19 | file_put_contents($this->filePath, $message); 20 | } 21 | } -------------------------------------------------------------------------------- /app/Patterns/Behavioral/Observer/NewUserSignedup/User.php: -------------------------------------------------------------------------------- 1 | _email = $email; 11 | $this->_phoneNum = $phoneNum; 12 | } 13 | 14 | public function getPhoneNo() 15 | { 16 | return $this->_phoneNum; 17 | } 18 | 19 | public function getEmail() 20 | { 21 | return $this->_email; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/Patterns/Creational/FactoryMethod/Logger/FileLoggerFactory.php: -------------------------------------------------------------------------------- 1 | filePath = $filePath; 10 | } 11 | /** 12 | * log to be printed on the screen 13 | * 14 | * @param null 15 | * @return void 16 | */ 17 | public function createLogger(): Logger 18 | { 19 | return new FileLogger($this->filePath); 20 | } 21 | } -------------------------------------------------------------------------------- /app/Patterns/Structural/RegisteryPattern/Exam/Application.php: -------------------------------------------------------------------------------- 1 | set(ExamRegistery::MID_TERM_EXAM, ['math', 'physics', 'optional subject']); 9 | $registery->set(ExamRegistery::FINAL_EXAM, ['math', 'physics']); 10 | 11 | $subjects = $registery->get(ExamRegistery::FINAL_EXAM); 12 | echo "
Final exam subject: ";print_r($subjects);
13 |   }
14 | }
15 | 


--------------------------------------------------------------------------------
/app/Patterns/Behavioral/ChainOfResponsibility/HandleHttpRequests/AbstractMiddleware.php:
--------------------------------------------------------------------------------
 1 | next = $next;
 9 | 
10 |     return $next;
11 |   }
12 | 
13 |   public function handle(Request $request)
14 |   {
15 |     if($this->next) {
16 |       return $this->next->handle($request);
17 |     }
18 |     return true;
19 |   }
20 | }
21 | 


--------------------------------------------------------------------------------
/app/Patterns/Creational/Pool/Worker/StringReverseWorker.php:
--------------------------------------------------------------------------------
 1 | created_at = new \DateTime; 
16 | 	}
17 | 	/*
18 | 	* Run
19 | 	*
20 | 	* @param null
21 | 	* @return null
22 | 	*/
23 | 	public function run(string $text)
24 | 	{
25 | 		return strrev($text);
26 | 	}
27 | }


--------------------------------------------------------------------------------
/app/Patterns/Structural/CompositePattern/Form/InputField.php:
--------------------------------------------------------------------------------
 1 | type = $type;
 9 |     parent::__construct($name, $title);
10 |   }
11 | 
12 |   public function render(): string {
13 |     return "
14 |       type}\" name=\"{$this->name}\" value=\"{$this->data}\" />";
15 |   }
16 | }


--------------------------------------------------------------------------------
/app/Patterns/Structural/DecoratorPattern/ActiveRecord/Application.php:
--------------------------------------------------------------------------------
 1 | 

All Users

'; 10 | foreach($user->all() as $u) { 11 | echo 'Name : ' . $u['name'] . ', Role: '. $u['role'] . "
"; 12 | } 13 | $admins = (new AdminFilter($user))->filter(); 14 | 15 | echo '

Admins filtered

'; 16 | foreach($admins as $u) { 17 | echo 'Name : ' . $u['name']; 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /app/Patterns/Creational/AbstractPattern/TvManufacturer/Television.php: -------------------------------------------------------------------------------- 1 | offset = $offset; 10 | $this->limit = $limit; 11 | return $this; 12 | } 13 | 14 | public function get() 15 | { 16 | $query = parent::get(); 17 | 18 | if($this->limit !== 0) { 19 | $query .= " LIMIT {$this->offset},{$this->limit}"; 20 | } 21 | return $query; 22 | } 23 | } -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "desingpatterns/php-design-pattern", 3 | "description": "PHP Design Patterns", 4 | "authors": [ 5 | { 6 | "name": "basheer", 7 | "email": "bsr.anwar@gmail.com" 8 | } 9 | ], 10 | "scripts": { 11 | "test": "phpunit" 12 | }, 13 | "autoload": { 14 | "psr-4": { 15 | "App\\": "app/" 16 | } 17 | }, 18 | "require": { 19 | "nikic/fast-route": "^1.2", 20 | "patricklouys/http": "^1.4", 21 | "curl/curl": "^2.3" 22 | }, 23 | "require-dev": { 24 | "phpunit/phpunit": "9.2" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/Patterns/Creational/StaticFactory/Suppliers/FlightSupplierFactory.php: -------------------------------------------------------------------------------- 1 | Logging via StdLogger'; 9 | $factory->createLogger()->log('Write this message to log'); 10 | 11 | echo '

Writing log to a file and reading from it

'; 12 | $file = __DIR__ . '/factory.txt'; 13 | (new FileLoggerFactory($file))->createLogger()->log('This text to be written on a file'); 14 | echo "
". file_get_contents($file); 15 | } 16 | } -------------------------------------------------------------------------------- /app/Patterns/Structural/BridgePattern/FlightApi/SabreFlightRenderer.php: -------------------------------------------------------------------------------- 1 | ID: {$id}
"; 8 | } 9 | 10 | public function renderTitle(string $title) 11 | { 12 | return "Title: {$title}
"; 13 | } 14 | 15 | public function renderOrigin(string $origin) 16 | { 17 | return "Origin {$origin}"; 18 | } 19 | 20 | public function renderDestination(string $dest) 21 | { 22 | return "Destination {$dest}"; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/Patterns/Structural/DecoratorPattern/ActiveRecord/AdminFilter.php: -------------------------------------------------------------------------------- 1 | _record = $record; 13 | } 14 | /** 15 | * filter all admins only 16 | * 17 | * @param null 18 | * @return array 19 | */ 20 | public function filter() 21 | { 22 | return \array_filter($this->_record->all(), function($user) { 23 | return $user['role'] === 'admin'; 24 | }); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/Patterns/Structural/BridgePattern/FlightApi/TravelportFlightRenderer.php: -------------------------------------------------------------------------------- 1 | ID: {$id}
"; 8 | } 9 | 10 | public function renderTitle(string $title) 11 | { 12 | return "Title: {$title}
"; 13 | } 14 | 15 | public function renderOrigin(string $origin) 16 | { 17 | return "Origin {$origin}"; 18 | } 19 | 20 | public function renderDestination(string $dest) 21 | { 22 | return "Destination {$dest}"; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/Patterns/Creational/FactoryMethod/CarManufacturer/GermanFactory.php: -------------------------------------------------------------------------------- 1 | Preparing Vegitable Meal'; 9 | $meal = $builder->prepareVegitable(); 10 | $meal->showItems(); 11 | echo '
meal cost is : ' . $meal->getCost();
12 |         $meal->forget();
13 |         
14 |         echo '

Preparing Non Vegitable Meal

'; 15 | $meal = $builder->prepareNonVegitable(); 16 | $meal->showItems(); 17 | echo '
meal cost is : ' . $meal->getCost();
18 | 		$meal->forget();
19 |     }
20 | }


--------------------------------------------------------------------------------
/app/Patterns/Creational/FactoryMethod/CarManufacturer/ItalianFactory.php:
--------------------------------------------------------------------------------
 1 | addItem(new VegitableBurger());
14 | 		$meal->addItem(new Coke());
15 | 		return $meal;
16 | 	}
17 | 	/*
18 | 	* Prepare Non VegitableBurger
19 | 	*
20 | 	* @param null
21 | 	* @return null
22 | 	*/
23 | 	public function prepareNonVegitable()
24 | 	{
25 | 		$meal = new Meal;
26 | 		$meal->addItem(new ChickenBurger());
27 | 		$meal->addItem(new Pepsi());
28 | 		return $meal;
29 | 	}
30 | }


--------------------------------------------------------------------------------
/app/Patterns/Structural/DataMapperPattern/UserMapper.php:
--------------------------------------------------------------------------------
 1 | storage = $storage;
12 |   }
13 | 
14 |   public function findById(int $id)
15 |   {
16 |     $data = $this->storage->find($id);
17 | 
18 |     if($data === null) {
19 |       throw new \InvalidArgumentException("User #$id not found");
20 |     }
21 |     return $this->mapRowToUser($data);
22 |   }
23 | 
24 |   public function mapRowToUser($data)
25 |   {
26 |     return User::fromState($data);
27 |   }
28 | }


--------------------------------------------------------------------------------
/tests/ProxyPatternTest.php:
--------------------------------------------------------------------------------
 1 | filePath);
11 | 
12 |     $this->assertTrue($fileReader->isReadable());
13 |   }
14 | 
15 |   public function testCanReadFileContent()
16 |   {
17 |     $fileReader = new App\Patterns\Structural\ProxyPattern\FileReader\JsonFileReaderProxy($this->filePath);
18 | 
19 |     $this->assertEquals($fileReader->getContent(), new \stdClass);
20 |   }
21 | }


--------------------------------------------------------------------------------
/app/Patterns/Structural/CompositePattern/Form/AbstractFormField.php:
--------------------------------------------------------------------------------
 1 | name = $name;
11 |     $this->title = $title;
12 |   }
13 | 
14 |   public function getName(): string
15 |   {
16 |     return $this->name;
17 |   }
18 | 
19 |   public function setData($data): void
20 |   {
21 |     $this->data = $data; 
22 |   }
23 | 
24 |   public function getData(): array
25 |   {
26 |     return $this->data;
27 |   }
28 | 
29 |   public abstract function render(): string;
30 | }


--------------------------------------------------------------------------------
/app/Patterns/Structural/DataMapperPattern/User.php:
--------------------------------------------------------------------------------
 1 | username = $username;
21 |     $this->email = $email;
22 |   }
23 | 
24 |   public function getUsername()
25 |   {
26 |     return $this->username;
27 |   }
28 |   
29 |   public function getEmail()
30 |   {
31 |     return $this->email;
32 |   }
33 | }


--------------------------------------------------------------------------------
/tests/AdapterPatternTest.php:
--------------------------------------------------------------------------------
 1 | assertEquals("Kids can move but can't walk", $kids->walk());
12 |        $this->assertEquals("Kids can smile or weep", $kids->speak());
13 |     }
14 | 
15 |     public function testMenCanWalkAndSpeak() {
16 |        $men = new Men;
17 |        $this->assertEquals("Men can walk", $men->walk());
18 |        $this->assertEquals("Men can speak", $men->speak());
19 |     }
20 | }
21 | 


--------------------------------------------------------------------------------
/app/Controller/BehavioralController.php:
--------------------------------------------------------------------------------
 1 | render();
 9 |   }
10 | 
11 |   public function commandApiScrapper()
12 |   {
13 |     (new \App\Patterns\Behavioral\Command\ApiScrapper\Application)->render();
14 |   }
15 | 
16 | 
17 |   public function hotelSupplierIterator()
18 |   {
19 |     (new \App\Patterns\Behavioral\Iterator\HotelSuppliers\Application)->render();
20 |   }
21 | 
22 |   public function signupObservers()
23 |   {
24 |     (new \App\Patterns\Behavioral\Observer\NewUserSignedup\Application)->render();
25 |   }
26 | }
27 | 


--------------------------------------------------------------------------------
/app/Patterns/Creational/Builder/Database/Application.php:
--------------------------------------------------------------------------------
 1 | select('users', ['user_id', 'user_name'])
 9 | 								->where('UserName = :userName', [':userName' => 'bsr.anwar'])
10 | 								->get();
11 | 		echo '
[Mysql Query] : ' . $query;
12 | 
13 | 		
14 | 		$postgresQuery = $builder->setDB('postgres')->select('users', ['user_id', 'user_name'])
15 | 											->where('UserName = :userName', [':userName' => 'khan'])
16 | 											->limit(0, 10)
17 | 											->get();
18 | 		echo '
[Postgres Query] : ' . $postgresQuery;
19 |     }
20 | }


--------------------------------------------------------------------------------
/tests/BridgeTest.php:
--------------------------------------------------------------------------------
 1 | assertStringContainsString('TICKETING WITH SABRE', $sabreTicket->view());
16 |   }
17 |   
18 |   public function testCheckTravelportTicketingView() {
19 |     $travelportTicket = new TravelportTicket(new TravelportFlightRenderer);
20 |     
21 |     $this->assertStringContainsString('TICKETING WITH TRAVELPORT', $travelportTicket->view());
22 |   }
23 | }


--------------------------------------------------------------------------------
/app/Patterns/Creational/FactoryMethod/CarManufacturer/Alto.php:
--------------------------------------------------------------------------------
 1 | setColor($color);
17 | 	}
18 | 	/*
19 | 	* Set Color
20 | 	*
21 | 	* @param null
22 | 	* @return null
23 | 	*/
24 | 	public function setColor(string $color)
25 | 	{
26 | 		$this->color = $color;
27 | 	}
28 | 	/*
29 | 	* Get Color
30 | 	*
31 | 	* @param null
32 | 	* @return null
33 | 	*/
34 | 	public function getColor() : string
35 | 	{
36 | 		return $this->color;
37 | 	}
38 | }


--------------------------------------------------------------------------------
/app/Patterns/Creational/AbstractPattern/TvManufacturer/Application.php:
--------------------------------------------------------------------------------
 1 | createSonyTv('lcd');
 9 | 
10 |         echo '

Creating Sony Lcd Tv

'; 11 | echo '
'. $sonyTv->addScreen();
12 |         echo '
'. $sonyTv->addPowerOption();
13 |         echo '
'. $sonyTv->make();
14 | 
15 |         $huwaiTv = $factory->createHuwaiTv('led');
16 | 
17 |         echo '

Creating Huwai Led Tv

'; 18 | echo '
'. $huwaiTv->addScreen();
19 |         echo '
'. $huwaiTv->addPowerOption();
20 |         echo '
'. $huwaiTv->make();
21 |     }
22 | }


--------------------------------------------------------------------------------
/app/Patterns/Creational/FactoryMethod/CarManufacturer/Ferrari.php:
--------------------------------------------------------------------------------
 1 | setColor($color);
17 | 	}
18 | 	/*
19 | 	* Set Color
20 | 	*
21 | 	* @param null
22 | 	* @return null
23 | 	*/
24 | 	public function setColor(string $color)
25 | 	{
26 | 		$this->color = $color;
27 | 	}
28 | 	/*
29 | 	* Get color
30 | 	*
31 | 	* @param null
32 | 	* @return null
33 | 	*/
34 | 	public function getColor() : string
35 | 	{
36 | 		return $this->color;
37 | 	}
38 | }


--------------------------------------------------------------------------------
/app/Patterns/Creational/FactoryMethod/CarManufacturer/Mehran.php:
--------------------------------------------------------------------------------
 1 | setColor($color);
17 | 	}
18 | 	/*
19 | 	* Set Color
20 | 	*
21 | 	* @param null
22 | 	* @return null
23 | 	*/
24 | 	public function setColor(string $color)
25 | 	{
26 | 		$this->color = $color;
27 | 	}
28 | 	/*
29 | 	* Get color
30 | 	*
31 | 	* @param null
32 | 	* @return null
33 | 	*/
34 | 	public function getColor() : string
35 | 	{
36 | 		return $this->color;
37 | 	}
38 | }


--------------------------------------------------------------------------------
/app/Patterns/Creational/FactoryMethod/CarManufacturer/Suzki.php:
--------------------------------------------------------------------------------
 1 | setColor($color);
18 | 	}
19 | 	/*
20 | 	* Set Color
21 | 	*
22 | 	* @param null
23 | 	* @return null
24 | 	*/
25 | 	public function setColor(string $color)
26 | 	{
27 | 		$this->color = $color;
28 | 	}
29 | 	/*
30 | 	* Get color
31 | 	*
32 | 	* @param null
33 | 	* @return null
34 | 	*/
35 | 	public function getColor() : string
36 | 	{
37 | 		return $this->color;
38 | 	}
39 | }


--------------------------------------------------------------------------------
/app/Commands/CreateTestFileCommand.php:
--------------------------------------------------------------------------------
 1 | _className = ucfirst($className);
14 |   }
15 |   /**
16 |   * create a test file
17 |   *
18 |   * @param null
19 |   * @return void
20 |   */
21 |   public function handle()
22 |   {
23 |     $stub = file_get_contents(__DIR__ . '/../../stubs/Test.stub');
24 |     $content = str_replace('class Test', 'class '. $this->_className, $stub);
25 |     file_put_contents(__DIR__ . '/../../tests/' . $this->_className . '.php', $content);
26 |     echo $this->_className . '.php File Created Succuessfully';
27 |   }
28 | }
29 | 


--------------------------------------------------------------------------------
/app/Patterns/Behavioral/Observer/NewUserSignedup/Application.php:
--------------------------------------------------------------------------------
 1 | [new user signed up]';
11 |     $observable = new NewUserSignedup(new User('bsr.anwar@gmail.com', '123123123'));
12 |     $observable->attach($observer1);
13 |     $observable->attach($observer2);
14 |     $observable->notify();
15 |     echo '
---Whatsapp observer detached---';
16 |     $observable->detach($observer1);
17 |     
18 |     echo '
[new user signed up]';
19 |     $observable->setUser(new User('foo@gmail.com', '123123123'));
20 |     $observable->notify();
21 |   }
22 | }
23 | 


--------------------------------------------------------------------------------
/app/Patterns/Structural/AdapterPattern/OperatingSystems/LinuxOperatingSystem.php:
--------------------------------------------------------------------------------
 1 | _command = $defaultCommand;
 9 |   }
10 |   /**
11 |   * considering "switchOff" as the functionality name for the IOS Operating system 
12 |   *
13 |   * @param null
14 |   * @return void
15 |   */
16 |   public function runCommand(string $command): void
17 |   {
18 |     $this->_command = $command;
19 |   }
20 |   /**
21 |   * get command
22 |   *
23 |   * @param null
24 |   * @return string
25 |   */
26 |   public function getCommand()
27 |   {
28 |     return $this->_command;
29 |   }
30 | }


--------------------------------------------------------------------------------
/tests/DecoratorPatternTest.php:
--------------------------------------------------------------------------------
 1 | all();
 9 | 
10 |     $roles = array_column($users, 'role');
11 |     $this->assertContains('admin', $roles);
12 |     $this->assertContains('hr', $roles);
13 |     $this->assertContains('software engineer', $roles);
14 |   }
15 | 
16 |   public function testCanFilterAdminsFromActiveRecordsList()
17 |   {
18 |     $user = new \App\Patterns\Structural\DecoratorPattern\ActiveRecord\User;
19 |     $admins = (new \App\Patterns\Structural\DecoratorPattern\ActiveRecord\AdminFilter($user))->filter();
20 |     $this->assertEquals('admin', $admins[0]['role']);
21 |   }
22 | }


--------------------------------------------------------------------------------
/app/Patterns/Creational/FactoryMethod/CarManufacturer/Application.php:
--------------------------------------------------------------------------------
 1 | create('fast', 'blue');
 9 | 
10 |         echo '

Manufacturing German Fast Cars

'; 11 | echo '
 car : ' . (new \ReflectionClass(get_class($vehicle)))->getShortName();
12 |         echo '
 color : ' . $vehicle->getColor();
13 |         
14 |         $factory = new ItalianFactory;
15 | 		$vehicle = $factory->create('cheap', 'red');
16 | 
17 |         echo '

Manufacturing Italian Cheap Cars

'; 18 | echo '
 car : ' . (new \ReflectionClass(get_class($vehicle)))->getShortName();
19 | 		echo '
 color : ' . $vehicle->getColor();
20 |     }
21 | }


--------------------------------------------------------------------------------
/app/Patterns/Creational/Builder/Database/DatabaseQueryBuilder.php:
--------------------------------------------------------------------------------
 1 | setDB($db);
10 |   }
11 | 
12 |   public function select(string $table, array $fields)
13 |   {
14 |     if($this->db->getConnection() === 'mysql') {
15 |       return (new MysqlQueryBuilder)->select($table, $fields);
16 |     }
17 |     return (new PostgresQueryBuilder)->select($table, $fields);
18 |   }
19 | 
20 |   public function getDB()
21 |   {
22 |     return $this->db;
23 |   }
24 | 
25 |   public function setDB($db)
26 |   {
27 |     if ($this->db) {
28 |       $this->db->disconnect();
29 |     }
30 |     $this->db = (new DB($db))->connect();
31 |     return $this;
32 |   }
33 | }
34 | 


--------------------------------------------------------------------------------
/tests/MailerDependencyInjectionTest.php:
--------------------------------------------------------------------------------
 1 | to(['foo@foo.com']);
20 |         $manager->cc(['biz@biz.com']);
21 |         $response = $manager->send();
22 | 
23 |         $this->assertStringContainsString('Sending email to recipients "foo@foo.com,biz@biz.com"', $response);
24 |     }
25 | }


--------------------------------------------------------------------------------
/app/Patterns/Structural/AdapterPattern/OperatingSystems/Operator.php:
--------------------------------------------------------------------------------
 1 | _os = $operatingSystem;
 8 |   }
 9 |   /**
10 |   * start the system
11 |   *
12 |   * @param null
13 |   * @return void
14 |   */
15 |   public function start()
16 |   {
17 |     return $this->_os->start();
18 |   }
19 |   /**
20 |   * shutdown the system
21 |   *
22 |   * @param null
23 |   * @return void
24 |   */
25 |   public function shutdown()
26 |   {
27 |     return $this->_os->shutdown();
28 |   }
29 |   /**
30 |   * get status of the operating system
31 |   *
32 |   * @param null
33 |   * @return void
34 |   */
35 |   public function getStatus()
36 |   {
37 |     return $this->_os->getStatus();
38 |   }
39 | }


--------------------------------------------------------------------------------
/app/Patterns/Structural/AdapterPattern/OperatingSystems/Application.php:
--------------------------------------------------------------------------------
 1 | shutdown();
11 |         echo '[[IOS status after shutdown]]: ' . $operator->getStatus();
12 |         $operator->start();
13 |         echo '
[[IOS status after start]]: ' . $operator->getStatus(); 14 | 15 | $linuxAdpt = new LinuxOperatingSystemAdapter(); 16 | $operator = new Operator($linuxAdpt); 17 | $operator->shutdown(); 18 | echo '


[[Linux status after shutdown]]: ' . $operator->getStatus(); 19 | $operator->start(); 20 | echo '
[[Linux status after start]]: ' . $operator->getStatus(); 21 | } 22 | } -------------------------------------------------------------------------------- /tests/CompositePatternTest.php: -------------------------------------------------------------------------------- 1 | add(new InputField('first_name', 'First Name', 'text')); 17 | $form->add(new InputField('last_name', 'Last Name', 'text')); 18 | 19 | $fieldSet = new Fieldset('login-details', 'Credentials'); 20 | $fieldSet->add(new InputField('email', 'Email', 'email')); 21 | $fieldSet->add(new InputField('Password', 'password', 'password')); 22 | 23 | $form->add($fieldSet); 24 | $this->assertStringContainsStringIgnoringCase('', $form->render()); 25 | } 26 | } -------------------------------------------------------------------------------- /tests/IteratorPatternTest.php: -------------------------------------------------------------------------------- 1 | current(); 18 | $this->assertSame($supplier->getHotels()[0]['title'], $hotelName); 19 | } 20 | 21 | public function testCanIteratorThroughDTWSupplierIterator() 22 | { 23 | $supplier = new DTWSupplier; 24 | $iterator = new DTWSupplierIterator($supplier); 25 | 26 | $hotelName = $iterator->current(); 27 | $this->assertSame($supplier->getHotels()[0]['name'], $hotelName); 28 | } 29 | } -------------------------------------------------------------------------------- /tests/AcmePrototypeTest.php: -------------------------------------------------------------------------------- 1 | setEmployee( $smith, "Tess Smith", 101, "ts101-1234"); 16 | 17 | $jacob = clone $marketing; 18 | $this->setEmployee( $jacob,"Jacob Jones", 102,"jj101-2234"); 19 | 20 | $this->assertEquals("Jacob Jones", $jacob->getName()); 21 | $this->assertEquals("Tess Smith", $smith->getName()); 22 | } 23 | 24 | private function setEmployee(IAcmePrototype $employee,$nm,$dp,$id) 25 | { 26 | $employee->setName($nm); 27 | $employee->setDept($dp); 28 | $employee->setID($id); 29 | } 30 | } -------------------------------------------------------------------------------- /app/Patterns/Behavioral/Command/ApiScrapper/AbstractApiScrapper.php: -------------------------------------------------------------------------------- 1 | _status; 20 | } 21 | 22 | public function getId(): int 23 | { 24 | return $this->id; 25 | } 26 | 27 | public function success(): void 28 | { 29 | $this->_status = self::SUCCESS; 30 | Queue::get()->completeCommand($this); 31 | } 32 | 33 | public function fail(): void 34 | { 35 | $this->_status = self::FAILED; 36 | Queue::get()->completeCommand($this); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/Patterns/Structural/DependencyInjectionPattern/Mailer/Drivers/Sendmail.php: -------------------------------------------------------------------------------- 1 | getRecipients()); 27 | return 'Sending email to recipients "' . $recipients . '" using driver sendmail'; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /tests/StaticFactoryTest.php: -------------------------------------------------------------------------------- 1 | get(1); 16 | 17 | $this->assertInstanceOf(TravelportSupplier::class, $factory); 18 | $this->assertStringContainsString('Book a flight', $factory->request('Book a flight')); 19 | } 20 | 21 | public function testFlightSupplierFactoryCanCreateTravelportSupplier() 22 | { 23 | $factory = (new FlightSupplierFactory())->get(2); 24 | 25 | $this->assertInstanceOf(SabreSupplier::class, $factory); 26 | $this->assertStringContainsString('Having issue booking a flight', $factory->request('Having issue booking a flight')); 27 | } 28 | } -------------------------------------------------------------------------------- /tests/RegisteryPatternTest.php: -------------------------------------------------------------------------------- 1 | setExam(ExamRegistery::FINAL_EXAM, $final_exam_subjects); 18 | 19 | $this->assertSame($final_exam_subjects, self::$registery->getExam(ExamRegistery::FINAL_EXAM)); 20 | } 21 | 22 | public function testCanThrowExceptionForInvalidKeys() 23 | { 24 | $this->expectException(\InvalidArgumentException::class); 25 | 26 | self::$registery->setExam('test', ''); 27 | } 28 | 29 | public function tearDown(): void 30 | { 31 | self::$registery = null; 32 | } 33 | } -------------------------------------------------------------------------------- /tests/StorageDataMapperTest.php: -------------------------------------------------------------------------------- 1 | ['username' => 'basheer', 'email' => 'basheer@octraves.com'] 16 | ]); 17 | 18 | $mapper = new UserMapper($stroage); 19 | $response = $mapper->findById(1); 20 | 21 | $this->assertInstanceOf(User::class, $response); 22 | $this->assertEquals('basheer', $response->getUsername()); 23 | } 24 | 25 | public function testCanThrowExceptionIfUserNotFound() 26 | { 27 | $this->expectException(\InvalidArgumentException::class); 28 | $stroage = new StorageDataMapper([]); 29 | 30 | $mapper = new UserMapper($stroage); 31 | $response = $mapper->findById(1); 32 | } 33 | } -------------------------------------------------------------------------------- /app/Patterns/Structural/ProxyPattern/FileReader/JsonFileReader.php: -------------------------------------------------------------------------------- 1 | _file = \json_decode(\file_get_contents($path)); 13 | $this->_fileSize = filesize($path); 14 | $this->_isWritable = is_writable($path); 15 | $this->_isReadable = is_readable($path); 16 | } 17 | 18 | public function getContent() 19 | { 20 | return $this->_file; 21 | } 22 | 23 | public function getFileSize(): int 24 | { 25 | return $this->_fileSize; 26 | } 27 | 28 | public function isWritable(): bool 29 | { 30 | return $this->_isWritable; 31 | } 32 | 33 | public function isReadable(): bool 34 | { 35 | return $this->_isReadable; 36 | } 37 | } -------------------------------------------------------------------------------- /app/Patterns/Creational/AbstractPattern/TvManufacturer/TvFactory.php: -------------------------------------------------------------------------------- 1 | dept = $this->research; 16 | break; 17 | 18 | case 202: 19 | $this->dept = $this->plan; 20 | break; 21 | 22 | case 203: 23 | $this->dept = $this->operations; 24 | break; 25 | 26 | default: 27 | $this->dept = "Unrecognized Management"; 28 | } 29 | } 30 | 31 | public function getDept() : string 32 | { 33 | return $this->dept; 34 | } 35 | 36 | public function __clone() {} 37 | } -------------------------------------------------------------------------------- /app/Patterns/Structural/AdapterPattern/OperatingSystems/IOSOperatingSystem.php: -------------------------------------------------------------------------------- 1 | _status = $status; 11 | } 12 | /** 13 | * shutdown the operating system 14 | * 15 | * @param null 16 | * @return void 17 | */ 18 | public function shutdown(): void 19 | { 20 | $this->_status = self::SHUT_DOWN; 21 | } 22 | /** 23 | * start the system 24 | * 25 | * @param null 26 | * @return void 27 | */ 28 | public function start() 29 | { 30 | $this->_status = self::START; 31 | } 32 | /** 33 | * Get the status of the operating system 34 | * 35 | * @param null 36 | * @return void 37 | */ 38 | public function getStatus() 39 | { 40 | return $this->_status; 41 | } 42 | } -------------------------------------------------------------------------------- /app/Patterns/Creational/Prototype/AcmePrototype/Engineering.php: -------------------------------------------------------------------------------- 1 | dept = $this->development; 16 | break; 17 | 18 | case 302: 19 | $this->dept = $this->design; 20 | break; 21 | 22 | case 303: 23 | $this->dept = $this->sysAd; 24 | break; 25 | 26 | default: 27 | $this->dept = "Unrecognized Engineering"; 28 | } 29 | } 30 | 31 | public function getDept() : string 32 | { 33 | return $this->dept; 34 | } 35 | 36 | public function __clone() {} 37 | } -------------------------------------------------------------------------------- /tests/FactoryMethod2Test.php: -------------------------------------------------------------------------------- 1 | createLogger(); 16 | $logger->log('Test text'); 17 | 18 | $this->expectOutputString('Test text'); 19 | $this->assertInstanceOf(StdLogger::class, $logger); 20 | } 21 | 22 | public function testCanWriteLogToFile() 23 | { 24 | $expectedString = 'Test Factory'; 25 | $file = __DIR__ . '/factory.txt'; 26 | $logger = (new FileLoggerFactory($file))->createLogger(); 27 | $logger->log($expectedString); 28 | 29 | $this->assertInstanceOf(FileLogger::class, $logger); 30 | $this->assertTrue(file_exists($file)); 31 | $content = file_get_contents($file); 32 | $this->assertEquals($content, $expectedString); 33 | } 34 | } -------------------------------------------------------------------------------- /tests/ObserverPatternTest.php: -------------------------------------------------------------------------------- 1 | attach(new ConfirmWhatsapp); 17 | 18 | $this->expectOutputString('
Sending verification code to: ' . $user->getPhoneNo());
19 |     $observable->notify();
20 |   }
21 | 
22 |   public function testUserCanNotifyEmailObserver()
23 |   {
24 |     $user = new User('basheer@octraves.com', '123123123');
25 |     $observable = new NewUserSignedup($user);
26 |     $observable->attach(new SendConfirmationEmail);
27 | 
28 |     $this->expectOutputString('
Sending confirmation email to: ' . $user->getEmail());
29 |     $observable->notify();
30 |   }
31 | }


--------------------------------------------------------------------------------
/app/Patterns/Structural/RegisteryPattern/Exam/ExamRegistery.php:
--------------------------------------------------------------------------------
 1 | addPowerOption();
34 |         $this->addScreen();
35 |         return implode(' ', $this->splitStudlyCaseToArr($this->getCalledClassName())) . ' is ready to be shipped';
36 |     }
37 | }


--------------------------------------------------------------------------------
/app/Patterns/Creational/AbstractPattern/TvManufacturer/HuwaiTvFactory.php:
--------------------------------------------------------------------------------
 1 | addPowerOption();
34 |         $this->addScreen();
35 |         return implode(' ', $this->splitStudlyCaseToArr($this->getCalledClassName())) . ' is ready to be shipped';
36 |     }
37 | }


--------------------------------------------------------------------------------
/app/Patterns/Creational/Prototype/AcmePrototype/Marketing.php:
--------------------------------------------------------------------------------
 1 | department = $this->sales;
20 | 				break;
21 | 			case 102:
22 | 				$this->department = $this->promotion;
23 | 				break;
24 | 			case 103:
25 | 				$this->department = $this->strategic;
26 | 				break;
27 | 			default:
28 | 				$this->department = "Unrecognized Marketing";
29 | 				break;
30 | 		}
31 | 	}
32 | 	/*
33 | 	* Get Department
34 | 	*
35 | 	* @param null
36 | 	* @return null
37 | 	*/
38 | 	public function getDept() : string
39 | 	{
40 | 		return $this->department;
41 | 	}
42 | 
43 | 	public function __clone() {}
44 | }


--------------------------------------------------------------------------------
/app/Patterns/Behavioral/Observer/NewUserSignedup/NewUserSignedup.php:
--------------------------------------------------------------------------------
 1 | _user = $user;
11 |   }
12 | 
13 |   public function attach(\SplObserver $observer)
14 |   {
15 |     $this->observers[] = $observer;
16 |   }
17 | 
18 |   public function detach(\SplObserver $observer)
19 |   {
20 |     foreach($this->observers as $k => $obs) {
21 |       if($observer === $obs) {
22 |         unset($this->observers[$k]);
23 |         break;
24 |       }
25 |     }
26 |   }
27 | 
28 |   public function notify(): void
29 |   {
30 |     foreach($this->observers as $observer) {
31 |       $observer->update($this);
32 |     }
33 |   }
34 | 
35 |   public function setUser(User $user)
36 |   {
37 |     $this->_user = $user;
38 |   }
39 | 
40 |   public function getUser()
41 |   {
42 |     return $this->_user;
43 |   }
44 | }
45 | 


--------------------------------------------------------------------------------
/app/Patterns/Structural/ProxyPattern/FileReader/JsonFileReaderProxy.php:
--------------------------------------------------------------------------------
 1 | _file = null;
11 |     $this->_path = $path;
12 |   }
13 | 
14 |   public function getContent()
15 |   {
16 |     $this->loadFile();
17 |     return $this->_file->getContent();
18 |   }
19 | 
20 |   public function getFileSize(): int
21 |   {
22 |     $this->loadFile();
23 |     return $this->_file->getFileSize();
24 |   }
25 | 
26 |   public function isWritable(): bool
27 |   {
28 |     $this->loadFile();
29 |     return $this->_file->isWritable();
30 |   }
31 |   
32 |   public function isReadable(): bool
33 |   {
34 |     $this->loadFile();
35 |     return $this->_file->isReadable();
36 |   }
37 | 
38 |   private function loadFile()
39 |   {
40 |     if($this->_file === null) {
41 |       $this->_file = new JsonFileReader($this->_path);
42 |     }
43 |   }
44 | }


--------------------------------------------------------------------------------
/app/Patterns/Structural/AdapterPattern/OperatingSystems/LinuxOperatingSystemAdapter.php:
--------------------------------------------------------------------------------
 1 | _linuxOS = new LinuxOperatingSystem();
10 |   }
11 |   /**
12 |   * shutdown the operating system
13 |   *
14 |   * @param null
15 |   * @return void
16 |   */
17 |   public function shutdown(): void
18 |   {
19 |     $this->_linuxOS->runCommand('shutdown');
20 |   }
21 |   /**
22 |   * start the system
23 |   *
24 |   * @param null
25 |   * @return void
26 |   */
27 |   public function start()
28 |   {
29 |     $this->_linuxOS->runCommand('start');
30 |   }
31 |   /**
32 |   * Get the status of the operating system
33 |   *
34 |   * @param null
35 |   * @return void
36 |   */
37 |   public function getStatus()
38 |   {
39 |     return $this->_linuxOS->getCommand() === 'shutdown' ? self::SHUT_DOWN : self::START;
40 |   }
41 | }


--------------------------------------------------------------------------------
/app/Patterns/Creational/Builder/Database/DB.php:
--------------------------------------------------------------------------------
 1 | connection = $connection;
10 |   }
11 |   /**
12 |   * connect to the database
13 |   *
14 |   * @param void
15 |   * @return self
16 |   */
17 |   public function connect()
18 |   {
19 |     $this->db = $this->connection;
20 |     return $this;
21 |   }
22 |   /**
23 |   * disconnect from database
24 |   *
25 |   * @param void
26 |   * @return self
27 |   */
28 |   public function disconnect()
29 |   {
30 |     $this->db = '';
31 |     return $this;
32 |   }
33 |   /**
34 |   * reconnect after disconnect
35 |   *
36 |   * @param void
37 |   * @return self
38 |   */
39 |   public function reconnect()
40 |   {
41 |     $this->connect();
42 |     return $this;
43 |   }
44 |   /**
45 |   * give the database connection
46 |   *
47 |   * @param void
48 |   * @return void
49 |   */
50 |   public function getConnection()
51 |   {
52 |     return $this->db;
53 |   }
54 | }


--------------------------------------------------------------------------------
/app/Patterns/Creational/AbstractPattern/TvManufacturer/TvHelper.php:
--------------------------------------------------------------------------------
 1 | getShortName();
38 |     }
39 | }


--------------------------------------------------------------------------------
/app/Patterns/Structural/Facade/Quickbooks/Application.php:
--------------------------------------------------------------------------------
 1 | createItem(['name' => 'cement', 'costcode' => 'ABE-222']);
10 |         
11 |         if(!$response) {
12 |             throw new \Exception('item could not be created');
13 |         }
14 |         echo "
item has been creatd successfully!"; 15 | 16 | $item = $facade->showItem(0); 17 | echo "
Item name: {$item['name']}
Costcode: {$item['costcode']}"; 18 | 19 | $updatdItem = ['name' => 'cement', 'costcode' => 'ABE-223']; 20 | $facade->updateItem(0, $updatdItem); 21 | echo "
Item '0' has been successfully updated
"; 22 | 23 | $facade->showItem(0); 24 | echo "
Item name: {$updatdItem['name']}
Costcode: {$updatdItem['costcode']}"; 25 | 26 | $facade->deleteItem(0); 27 | echo "
Item '0' has been successfully deleted
"; 28 | } 29 | } -------------------------------------------------------------------------------- /app/Patterns/Structural/CompositePattern/Form/FieldComposite.php: -------------------------------------------------------------------------------- 1 | fields[$field->getName()] = $field; 9 | } 10 | 11 | public function remove(AbstractFormField $field) 12 | { 13 | $this->fields = array_filter($this->fields, function($item) use ($field) { 14 | return $item != $field; 15 | }); 16 | } 17 | 18 | public function setData($data): void 19 | { 20 | foreach($this->fields as $name => $field) { 21 | if(isset($data[$name])) { 22 | $field->setData($name); 23 | } 24 | } 25 | } 26 | 27 | public function getData(): array 28 | { 29 | $data = []; 30 | foreach($this->fields as $name => $field) { 31 | $data[$name] = $field->getData(); 32 | } 33 | return $data; 34 | } 35 | 36 | public function render(): string 37 | { 38 | $output = ''; 39 | 40 | foreach($this->fields as $field) { 41 | $output .= $field->render(); 42 | } 43 | return $output; 44 | } 45 | } -------------------------------------------------------------------------------- /app/Patterns/Structural/Facade/Quickbooks/QuickbooksItems.php: -------------------------------------------------------------------------------- 1 | items[] = $item; 12 | return true; 13 | } 14 | 15 | public function fetch(int $itemID): array 16 | { 17 | if(!isset($this->items[$itemID])) { 18 | throw new QuickBooksItemNotFoundException($itemID); 19 | } 20 | return $this->items[$itemID]; 21 | } 22 | 23 | public function update(int $itemID, array $fields): bool 24 | { 25 | if(!isset($this->items[$itemID])) { 26 | throw new QuickBooksItemNotFoundException($itemID); 27 | } 28 | 29 | $this->items[$itemID] = array_merge($this->items[$itemID], $fields); 30 | return true; 31 | } 32 | 33 | public function delete(int $itemID): bool 34 | { 35 | if(!isset($this->items[$itemID])) { 36 | throw new QuickBooksItemNotFoundException($itemID); 37 | } 38 | unset($this->items[$itemID]); 39 | return true; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/Patterns/Creational/Prototype/AcmePrototype/IAcmePrototype.php: -------------------------------------------------------------------------------- 1 | name = $name; 29 | } 30 | /* 31 | * Get name 32 | * 33 | * @param null 34 | * @return null 35 | */ 36 | public function getName() 37 | { 38 | return $this->name; 39 | } 40 | /* 41 | * Set Id 42 | * 43 | * @param null 44 | * @return null 45 | */ 46 | public function setId($id) 47 | { 48 | $this->id = $id; 49 | } 50 | /* 51 | * Get id 52 | * 53 | * @param null 54 | * @return null 55 | */ 56 | public function getId() 57 | { 58 | return $this->id; 59 | } 60 | /* 61 | * Clone 62 | * 63 | * @param null 64 | * @return null 65 | */ 66 | abstract function __clone(); 67 | } -------------------------------------------------------------------------------- /tests/WorkerPoolTest.php: -------------------------------------------------------------------------------- 1 | get(); 17 | $worker2 = $pool->get(); 18 | 19 | $this->assertCount(2, $pool); 20 | $this->assertNotSame($worker1, $worker2); 21 | } 22 | /** 23 | * reuse the same instance after disposing 24 | * 25 | * @param void 26 | * @return void 27 | */ 28 | public function testCanGetSameInstanceTwiceWhenDisposing() 29 | { 30 | $pool = new WorkerPool; 31 | $worker1 = $pool->get(); 32 | $pool->dispose($worker1); 33 | $worker2 = $pool->get(); 34 | 35 | $this->assertCount(1, $pool); 36 | $this->assertSame($worker1, $worker2); 37 | } 38 | /** 39 | * throw error on exceeding the worker limit 40 | * 41 | * @param void 42 | * @return void 43 | */ 44 | public function testShouldThrowExceptionOnExceedingLimit() 45 | { 46 | $this->expectException(\Exception::class); 47 | $pool = new WorkerPool; 48 | for($i = 0; $i < 20; $i++) { 49 | $pool->get(); 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /bootstraps/autoload.php: -------------------------------------------------------------------------------- 1 | getHeaders() as $header) 8 | { 9 | header($header, false); 10 | } 11 | $routeDefinitionCallback = function (\FastRoute\RouteCollector $r) { 12 | $routes = include('routes.php'); 13 | foreach ($routes as $route) { 14 | $r->addRoute($route[0], $route[1], $route[2]); 15 | } 16 | }; 17 | $dispatcher = \FastRoute\simpleDispatcher($routeDefinitionCallback); 18 | $routeInfo = $dispatcher->dispatch($request->getMethod(), $request->getPath()); 19 | switch ($routeInfo[0]) { 20 | case \FastRoute\Dispatcher::NOT_FOUND: 21 | $response->setContent('404 - Page not found'); 22 | $response->setStatusCode(404); 23 | break; 24 | case \FastRoute\Dispatcher::METHOD_NOT_ALLOWED: 25 | $response->setContent('405 - Method not allowed'); 26 | $response->setStatusCode(405); 27 | break; 28 | case \FastRoute\Dispatcher::FOUND: 29 | $className = $routeInfo[1][0]; 30 | $method = $routeInfo[1][1]; 31 | $vars = $routeInfo[2]; 32 | 33 | $class = new $className; 34 | $class->$method($vars); 35 | break; 36 | } -------------------------------------------------------------------------------- /app/Patterns/Structural/CompositePattern/Form/Application.php: -------------------------------------------------------------------------------- 1 | createProductForm(); 9 | $this->loadProductData($product); 10 | $this->renderProduct($product); 11 | } 12 | 13 | public function createProductForm() 14 | { 15 | $form = new Form('product', 'Add Product', 'product/add'); 16 | $form->add(new InputField('name', 'Name', 'text')); 17 | $form->add(new InputField('description', 'description', 'text')); 18 | 19 | $fieldset = new Fieldset('photo', 'Product Photo'); 20 | $fieldset->add(new InputField('caption', 'Caption', 'text')); 21 | $fieldset->add(new InputField('image', 'Image', 'file')); 22 | 23 | $form->add($fieldset); 24 | 25 | return $form; 26 | } 27 | 28 | public function loadProductData(AbstractFormField $form) 29 | { 30 | $data = [ 31 | 'name' => 'Apple MacBook', 32 | 'description' => 'A decent laptop', 33 | 'photo' => [ 34 | 'caption' => 'Front Photo', 35 | 'image' => 'photo1.jpg' 36 | ] 37 | ]; 38 | $form->setData($data); 39 | } 40 | 41 | public function renderProduct(AbstractFormField $form) 42 | { 43 | echo $form->render(); 44 | } 45 | } -------------------------------------------------------------------------------- /tests/FacadeTest.php: -------------------------------------------------------------------------------- 1 | 'cement', 'costcode' => 'ABE-222']; 8 | 9 | public function setUp(): void 10 | { 11 | $this->facade = new \App\Patterns\Structural\Facade\Quickbooks\QuickbooksFacade('test123'); 12 | $this->facade->createItem($this->defaulItem); 13 | } 14 | 15 | public function testQuickbooksFacadeCanCreateItem() { 16 | $this->facade = new \App\Patterns\Structural\Facade\Quickbooks\QuickbooksFacade('test123'); 17 | 18 | $this->assertTrue($this->facade->createItem($this->defaulItem)); 19 | } 20 | 21 | public function testQuickbooksFacadeCanReturnTheCreatedItem() { 22 | $item = $this->facade->showItem(0); 23 | $this->assertEquals($this->defaulItem, $item); 24 | } 25 | 26 | public function testQuickbooksFacadeCanUpdateTheItem() { 27 | $updatedItem = ['name' => 'Plumbing', 'costcode' => 'BDD-222']; 28 | $response = $this->facade->updateItem(0, $updatedItem); 29 | 30 | $this->assertTrue($response); 31 | $this->assertEquals($updatedItem, $this->facade->showItem(0)); 32 | } 33 | 34 | public function testQuickbooksFacadeCanDeleteItem() { 35 | $this->assertTrue($this->facade->deleteItem(0)); 36 | } 37 | 38 | } -------------------------------------------------------------------------------- /tests/AdapaterPatternExample2Test.php: -------------------------------------------------------------------------------- 1 | shutdown(); 20 | $statusAfterShutdown = $operator->getStatus(); 21 | $operator->start(); 22 | 23 | $this->assertEquals(LinuxOperatingSystemAdapter::SHUT_DOWN, $statusAfterShutdown); 24 | $this->assertEquals(LinuxOperatingSystemAdapter::START, $operator->getStatus()); 25 | } 26 | 27 | public function testOperatorCanStartAndShutdownIOSOperatingSystem() { 28 | $ios = new IOSOperatingSystem; 29 | 30 | $operator = new Operator($ios); 31 | $operator->shutdown(); 32 | $statusAfterShutdown = $operator->getStatus(); 33 | $operator->start(); 34 | 35 | $this->assertEquals(IOSOperatingSystem::SHUT_DOWN, $statusAfterShutdown); 36 | $this->assertEquals(IOSOperatingSystem::START, $operator->getStatus()); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /tests/ChainOfResponsibilityTest.php: -------------------------------------------------------------------------------- 1 | expectOutputString('Guest Dashboard', $app->render()); 12 | } 13 | 14 | public function testApplicationCanRenderAuthUserPage() 15 | { 16 | $_GET = ['uri' => 'auth', 'user' => 'basheer']; 17 | $app = new \App\Patterns\Behavioral\ChainOfResponsibility\HandleHttpRequests\Application; 18 | 19 | $this->expectOutputString('simple auth user page', $app->render()); 20 | } 21 | 22 | public function testApplicationCanRenderAdminPage() 23 | { 24 | $_GET = ['uri' => 'admin', 'user' => 'basheer', 'role' => 'admin']; 25 | $app = new \App\Patterns\Behavioral\ChainOfResponsibility\HandleHttpRequests\Application; 26 | 27 | $this->expectOutputString('Admin Dashboard', $app->render()); 28 | } 29 | 30 | public function testApplicationCanThrowErrorOnWrongAdminUser() 31 | { 32 | $this->expectException(\Exception::class); 33 | $_GET = ['uri' => 'admin', 'user' => 'base', 'role' => 'admin']; 34 | $app = new \App\Patterns\Behavioral\ChainOfResponsibility\HandleHttpRequests\Application; 35 | $app->render(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/Patterns/Creational/Pool/Worker/WorkerPool.php: -------------------------------------------------------------------------------- 1 | count() > 10) { 22 | throw new \Exception('Worker limit reached'); 23 | } 24 | if(count($this->freeWorkers) == 0) { 25 | $worker = new StringReverseWorker; 26 | } else { 27 | $worker = array_pop($this->freeWorkers); 28 | } 29 | $this->occupiedWorkers[spl_object_hash($worker)] = $worker; 30 | 31 | return $worker; 32 | } 33 | /* 34 | * Dispose 35 | * 36 | * @param null 37 | * @return null 38 | */ 39 | public function dispose(StringReverseWorker $worker) 40 | { 41 | $key = spl_object_hash($worker); 42 | if(isset($this->occupiedWorkers[$key])) { 43 | unset($this->occupiedWorkers[$key]); 44 | $this->freeWorkers[$key] = $worker; 45 | } 46 | } 47 | /* 48 | * Count 49 | * 50 | * @param null 51 | * @return null 52 | */ 53 | public function count() 54 | { 55 | return count($this->occupiedWorkers) + count($this->freeWorkers); 56 | } 57 | } -------------------------------------------------------------------------------- /app/Controller/StructuralController.php: -------------------------------------------------------------------------------- 1 | render(); 10 | } 11 | 12 | public function osAdapter() 13 | { 14 | (new \App\Patterns\Structural\AdapterPattern\OperatingSystems\Application)->render(); 15 | } 16 | 17 | public function facadeQuickbooks() 18 | { 19 | (new \App\Patterns\Structural\Facade\Quickbooks\Application)->render(); 20 | } 21 | 22 | public function bridgeFlights() 23 | { 24 | (new \App\Patterns\Structural\BridgePattern\FlightApi\Application)->render(); 25 | } 26 | 27 | public function compositeForm() 28 | { 29 | (new \App\Patterns\Structural\CompositePattern\Form\Application)->run(); 30 | } 31 | 32 | public function decoratorActiveRecord() 33 | { 34 | (new \App\Patterns\Structural\DecoratorPattern\ActiveRecord\Application)->run(); 35 | } 36 | 37 | public function proxyFileReader() 38 | { 39 | (new \App\Patterns\Structural\ProxyPattern\FileReader\Application)->run(); 40 | } 41 | 42 | public function dependencyInjectionMailer() 43 | { 44 | (new \App\Patterns\Structural\DependencyInjectionPattern\Mailer\Application)->run(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /app/Patterns/Creational/Prototype/AcmePrototype/Application.php: -------------------------------------------------------------------------------- 1 | setEmployee( $smith, "Tess Smith", 101, "ts101-1234"); 13 | $this->showEmployee($smith); 14 | 15 | $jacob = clone $marketing; 16 | $this->setEmployee( $jacob,"Jacob Jones", 102,"jj101-2234"); 17 | $this->showEmployee($jacob); 18 | 19 | $ricky = clone $management; 20 | $this->setEmployee($ricky,"Ricky Rodriguez", 203,"rr203-5634"); 21 | $this->showEmployee($ricky); 22 | 23 | $livia = clone $engineering; 24 | $this->setEmployee($livia,"Olivia Perez", 302,"op301-1278"); 25 | $this->showEmployee($livia); 26 | 27 | $jhon = clone $engineering; 28 | $this->setEmployee($jhon,"John Jackson", 301, "jj302-1454"); 29 | $this->showEmployee($jhon); 30 | } 31 | 32 | private function showEmployee(IAcmePrototype $employee) 33 | { 34 | echo $employee->getName() . "
"; 35 | echo $employee->getDept() . ": " . $employee::UNIT . "
"; 36 | echo $employee->getID() . "

"; 37 | } 38 | 39 | private function setEmployee(IAcmePrototype $employee,$nm,$dp,$id) 40 | { 41 | $employee->setName($nm); 42 | $employee->setDept($dp); 43 | $employee->setID($id); 44 | } 45 | } -------------------------------------------------------------------------------- /app/Patterns/Behavioral/Iterator/HotelSuppliers/DTWSupplierIterator.php: -------------------------------------------------------------------------------- 1 | _hotels = $supplier->getHotels(); 14 | } 15 | /** 16 | * current element 17 | * 18 | * @param null 19 | * @return string 20 | */ 21 | public function current(): string 22 | { 23 | return $this->_hotels[$this->_counter]['name']; 24 | } 25 | /** 26 | * get the current index 27 | * 28 | * @param null 29 | * @return int 30 | */ 31 | public function key(): int 32 | { 33 | return $this->_counter; 34 | } 35 | /** 36 | * get the next element in the array 37 | * 38 | * @param null 39 | * @return void 40 | */ 41 | public function next(): void 42 | { 43 | $this->_counter++; 44 | } 45 | /** 46 | * check weather we have next element in the array 47 | * 48 | * @param null 49 | * @return bool 50 | */ 51 | public function valid(): bool 52 | { 53 | return (count($this->_hotels) - 1) > $this->_counter; 54 | } 55 | /** 56 | * rewind from the start 57 | * 58 | * @param null 59 | * @return void 60 | */ 61 | public function rewind(): void 62 | { 63 | $this->_counter = 0; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /app/Patterns/Behavioral/Iterator/HotelSuppliers/HTOSupplierIterator.php: -------------------------------------------------------------------------------- 1 | _hotels = $supplier->getHotels(); 14 | } 15 | /** 16 | * current element 17 | * 18 | * @param null 19 | * @return string 20 | */ 21 | public function current(): string 22 | { 23 | return $this->_hotels[$this->_counter]['title']; 24 | } 25 | /** 26 | * get the current index 27 | * 28 | * @param null 29 | * @return int 30 | */ 31 | public function key(): int 32 | { 33 | return $this->_counter; 34 | } 35 | /** 36 | * get the next element in the array 37 | * 38 | * @param null 39 | * @return void 40 | */ 41 | public function next(): void 42 | { 43 | $this->_counter++; 44 | } 45 | /** 46 | * check weather we have next element in the array 47 | * 48 | * @param null 49 | * @return bool 50 | */ 51 | public function valid(): bool 52 | { 53 | return (count($this->_hotels) - 1) > $this->_counter; 54 | } 55 | /** 56 | * rewind from the start 57 | * 58 | * @param null 59 | * @return void 60 | */ 61 | public function rewind(): void 62 | { 63 | $this->_counter = 0; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /tests/FactoryMethodTest.php: -------------------------------------------------------------------------------- 1 | create(FactoryMethod::FAST, 'yellow'); 18 | $car2 = $factory->create(FactoryMethod::CHEAP, 'red'); 19 | 20 | $this->assertInstanceOf(Alto::class, $car); 21 | $this->assertInstanceOf(Suzki::class, $car2); 22 | } 23 | 24 | public function testCanCreateAItalianVehicle() 25 | { 26 | $factory = new ItalianFactory; 27 | $car = $factory->create(FactoryMethod::FAST, 'blue'); 28 | $car2 = $factory->create(FactoryMethod::CHEAP, 'green'); 29 | 30 | $this->assertInstanceOf(Ferrari::class, $car); 31 | $this->assertInstanceOf(Mehran::class, $car2); 32 | } 33 | 34 | 35 | public function testUnknownType() 36 | { 37 | $this->expectException(\InvalidArgumentException::class); 38 | (new ItalianFactory)->create('spaceship', 'white'); 39 | } 40 | } -------------------------------------------------------------------------------- /tests/CommandTest.php: -------------------------------------------------------------------------------- 1 | assertTrue($queue->isEmpty()); 17 | } 18 | 19 | public function testCanAddNewCommandsToQueue() 20 | { 21 | $queue = Queue::get(); 22 | 23 | $defaultCommand = new KlookApiScrapper(new \App\Patterns\Behavioral\Command\ApiScrapper\JsonApiManager); 24 | $queue->add($defaultCommand); 25 | 26 | $command = $queue->getCommand(); 27 | $this->assertEquals($defaultCommand->getStatus(), $command->getStatus()); 28 | } 29 | 30 | public function testQueueCanCompleteCommand() 31 | { 32 | $queue = Queue::get(); 33 | 34 | $defaultCommand = new KlookApiScrapper(new \App\Patterns\Behavioral\Command\ApiScrapper\JsonApiManager); 35 | $queue->add($defaultCommand); 36 | // complete the command 37 | $defaultCommand = $queue->getCommand(); 38 | $defaultCommand->success(); 39 | 40 | // get the command back again from the db 41 | $command = $queue->setStatus(AbstractApiScrapper::SUCCESS)->getCommand(); 42 | $this->assertEquals(AbstractApiScrapper::SUCCESS, $command->getStatus()); 43 | } 44 | } -------------------------------------------------------------------------------- /app/Patterns/Behavioral/ChainOfResponsibility/HandleHttpRequests/Application.php: -------------------------------------------------------------------------------- 1 | [ 8 | AuthMiddleware::class, 9 | AdminMiddleware::class 10 | ], 11 | 'auth' => [ 12 | AuthMiddleware::class, 13 | ], 14 | 'guest' => [ 15 | GuestMiddleware::class, 16 | ] 17 | ]; 18 | 19 | 20 | public function __construct() 21 | { 22 | $this->bootstrap(); 23 | } 24 | 25 | public function bootstrap() 26 | { 27 | $this->_request = new Request($_GET); 28 | 29 | $middlewares = $this->middlewares[$this->_request->uri] ?? $this->middlewares['guest']; 30 | 31 | foreach ($middlewares as $middleware) { 32 | if(!(new $middleware())->handle($this->_request)) { 33 | throw new \Exception('access denied'); 34 | } 35 | } 36 | } 37 | 38 | public function render() 39 | { 40 | if ($this->_request->uri === 'admin') { 41 | $this->adminPage(); 42 | } else if ($this->_request->uri === 'auth') { 43 | $this->authUserPage(); 44 | } else { 45 | $this->guestPage(); 46 | } 47 | } 48 | 49 | public function adminPage() 50 | { 51 | echo 'Admin Dashboard'; 52 | } 53 | 54 | public function guestPage() 55 | { 56 | echo 'Guest Dashboard'; 57 | } 58 | 59 | public function authUserPage() 60 | { 61 | echo 'simple auth user page'; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /app/Patterns/Creational/Builder/Resturant/Meal.php: -------------------------------------------------------------------------------- 1 | items[] = $item; 14 | return $this; 15 | } 16 | /* 17 | * Get cost 18 | * 19 | * @param null 20 | * @return null 21 | */ 22 | public function getCost() 23 | { 24 | return array_sum(array_map(function($item) { 25 | return $item->price(); 26 | }, $this->items)); 27 | } 28 | /* 29 | * Show Items 30 | * 31 | * @param null 32 | * @return null 33 | */ 34 | public function showItems() 35 | { 36 | echo ''; 37 | foreach ($this->items as $k => $item) { 38 | echo ''; 39 | echo ''; 40 | echo ''; 41 | echo ''; 42 | echo ''; 43 | } 44 | echo '
Item : ' . $item->name() . ' Packing : ' . $item->packing()->pack() . ' Price : ' . $item->price() . '
'; 45 | } 46 | /* 47 | * Get Items 48 | * 49 | * @param null 50 | * @return null 51 | */ 52 | public function first() 53 | { 54 | return reset($this->items); 55 | } 56 | /* 57 | * last 58 | * 59 | * @param null 60 | * @return null 61 | */ 62 | public function last() 63 | { 64 | return end($this->items); 65 | } 66 | /* 67 | * Call 68 | * 69 | * @param null 70 | * @return null 71 | */ 72 | public function __call($name, $arguments) 73 | { 74 | if($name === 'forget') { 75 | $this->items = []; 76 | } 77 | } 78 | } -------------------------------------------------------------------------------- /app/Patterns/Behavioral/Command/ApiScrapper/KlookApiScrapper.php: -------------------------------------------------------------------------------- 1 | _offset = $offset; 14 | $this->_http = $http; 15 | } 16 | 17 | public function execute(): void 18 | { 19 | $request = [ 20 | 'limit' => $this->_limit, 'offset' => $this->_offset, 21 | 'fields' => 'activity_id,title,price,category_id,country_id,published' 22 | ]; 23 | 24 | try { 25 | $response = $this->_http->setHeaders([ 26 | 'X-API-KEY' => $this->_authKey 27 | ]) 28 | ->get($this->_url, $request); 29 | $this->map($response); 30 | $this->success(); 31 | } catch (\Exception $e) { 32 | $this->fail(); 33 | } 34 | 35 | } 36 | 37 | public function map($response): void 38 | { 39 | foreach($response->activities as $activity) { 40 | echo "Scrapped: " . $activity->title . '
'; 41 | } 42 | 43 | if(isset($response->links->next)) { 44 | $offset = $this->_offset + $this->_limit; 45 | Queue::get()->add(new KlookApiScrapper($this->_http, $offset)); 46 | } 47 | } 48 | 49 | public function getOffset() 50 | { 51 | return $this->_offset; 52 | } 53 | } -------------------------------------------------------------------------------- /app/Patterns/Behavioral/Command/ApiScrapper/JsonApiManager.php: -------------------------------------------------------------------------------- 1 | _headers = $headers; 17 | return $this; 18 | } 19 | 20 | protected function getHeaders() 21 | { 22 | return \array_merge([ 23 | 'Content-Type'=>'application/json', 24 | 'cache-control' => 'no-cache', 25 | 'Accept-Language' => 'en_US' 26 | ], $this->_headers); 27 | } 28 | 29 | public function get(string $url, array $request = []){ 30 | return $this->execute($url, $request ); 31 | } 32 | 33 | private function execute(string $url, $request, $type = 'GET') { 34 | $curl = new Curl(); 35 | 36 | foreach ($this->getHeaders() as $key => $value) { 37 | $curl->setHeader($key, $value); 38 | } 39 | 40 | $curl->setOpt(CURLOPT_RETURNTRANSFER, 1); 41 | $curl->setOpt(CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); 42 | 43 | switch ($type) { 44 | case 'GET': 45 | if ($request != null) { 46 | $url .= '?'.http_build_query($request); 47 | } 48 | $curl->get($url); 49 | break; 50 | case 'POST': 51 | $curl->setOpt(CURLOPT_CUSTOMREQUEST, 'POST'); 52 | $curl->post($url, json_encode($request) ); 53 | break; 54 | default: 55 | return FALSE; 56 | } 57 | return json_decode($curl->response); 58 | } 59 | } -------------------------------------------------------------------------------- /app/Patterns/Structural/Facade/Quickbooks/QuickbooksFacade.php: -------------------------------------------------------------------------------- 1 | apiKey = $apiKey; 10 | $this->quickbookItems = new QuickbooksItems(); 11 | } 12 | 13 | public function connect(): void 14 | { 15 | // echo '
Connected to quickbooks via: ' . $this->apiKey; 16 | } 17 | 18 | public function createItem(array $item): bool 19 | { 20 | $this->connect(); 21 | 22 | $response = $this->quickbookItems->create($item); 23 | 24 | $this->disconnect(); 25 | 26 | return $response; 27 | } 28 | 29 | public function showItem(int $itemID): array 30 | { 31 | $this->connect(); 32 | 33 | $item = $this->quickbookItems->fetch($itemID); 34 | 35 | $this->disconnect(); 36 | 37 | return $item; 38 | } 39 | 40 | public function updateItem(int $itemID, array $fields): bool 41 | { 42 | $this->connect(); 43 | 44 | $response = $this->quickbookItems->update($itemID, $fields); 45 | 46 | $this->disconnect(); 47 | 48 | return $response; 49 | } 50 | 51 | public function deleteItem(int $itemID): bool 52 | { 53 | $this->connect(); 54 | 55 | $response = $this->quickbookItems->delete($itemID); 56 | 57 | $this->disconnect(); 58 | 59 | return $response; 60 | } 61 | 62 | public function disconnect(): void 63 | { 64 | // echo '
Disconnected from quickbooks
'; 65 | } 66 | } -------------------------------------------------------------------------------- /app/Patterns/Structural/DependencyInjectionPattern/Mailer/MailManager.php: -------------------------------------------------------------------------------- 1 | mailer = $mailer; 23 | } 24 | 25 | /** 26 | * sends email 27 | * 28 | * @param void 29 | * @return string 30 | */ 31 | public function send(): string 32 | { 33 | $this->mailer->connect(); 34 | return $this->mailer->send($this); 35 | } 36 | 37 | /** 38 | * sets 'to' recipients for the email 39 | * 40 | * @param array $recipients 41 | * @return void 42 | */ 43 | public function to(array $recipients): void 44 | { 45 | $this->toRecipients = $recipients; 46 | } 47 | 48 | /** 49 | * sets 'cc' recipients for the email 50 | * 51 | * @param array $recipients 52 | * @return void 53 | */ 54 | public function cc(array $recipients): void 55 | { 56 | $this->ccRecipients = $recipients; 57 | } 58 | 59 | /** 60 | * get all the recipients 61 | * 62 | * @param void 63 | * @return array 64 | */ 65 | public function getRecipients(): array 66 | { 67 | return array_merge($this->toRecipients, $this->ccRecipients); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /app/Patterns/Creational/Builder/Database/MysqlQueryBuilder.php: -------------------------------------------------------------------------------- 1 | table = $table; 12 | $this->fields = $fields; 13 | return $this; 14 | } 15 | 16 | public function where(string $condition, array $params) 17 | { 18 | $this->condition = $condition; 19 | $this->params = $params; 20 | return $this; 21 | } 22 | 23 | public function count(string $col = null) 24 | { 25 | $query = 'SELECT COUNT(' . $col . ') FROM `' . $this->table . '`'; 26 | 27 | if(count($this->params) > 0) { 28 | $query .= ' WHERE(' . implode(',', $this->params) . ')'; 29 | } 30 | 31 | return $query; 32 | } 33 | 34 | public function get() 35 | { 36 | $query = 'SELECT ' . implode(',', $this->fields) . ' FROM `' . $this->table . '`'; 37 | 38 | if(count($this->params) > 0) { 39 | foreach($this->params as $k => $v) { 40 | $this->condition = str_replace($k, $v, $this->condition); 41 | } 42 | $query .= ' WHERE ' . $this->condition; 43 | } 44 | 45 | return $query; 46 | } 47 | 48 | public function __call($command, $arguments) 49 | { 50 | $class_methos = get_class_methods(__CLASS__); 51 | 52 | if(!in_array($command, $class_methos)) { 53 | throw new \BadMethodCallException("Method {$command} not defined on {get_class_name()}"); 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /app/Controller/CreationalController.php: -------------------------------------------------------------------------------- 1 | render(); 19 | } 20 | /* 21 | * Builder 22 | * 23 | * @param null 24 | * @return null 25 | */ 26 | public function resturantBuilder() 27 | { 28 | (new \App\Patterns\Creational\Builder\Resturant\Application)->render(); 29 | } 30 | /* 31 | * Builder 32 | * 33 | * @param null 34 | * @return null 35 | */ 36 | public function databaseBuilder() 37 | { 38 | (new \App\Patterns\Creational\Builder\Database\Application)->render(); 39 | } 40 | /* 41 | * simple factory or factory method 42 | * 43 | * @param null 44 | * @return null 45 | */ 46 | public function carManufactureFactoryMethod() 47 | { 48 | (new \App\Patterns\Creational\FactoryMethod\CarManufacturer\Application)->render(); 49 | } 50 | /* 51 | * simple factory or factory method 52 | * 53 | * @param null 54 | * @return null 55 | */ 56 | public function loggerFactoryMethod() 57 | { 58 | (new \App\Patterns\Creational\FactoryMethod\Logger\Application)->render(); 59 | } 60 | /* 61 | * reverse string 62 | * 63 | * @param null 64 | * @return null 65 | */ 66 | public function reverseString() 67 | { 68 | $pool = new WorkerPool; 69 | $worker = $pool->get(); 70 | 71 | echo ' Reverse the following string by worker: do some job = ' . $worker->run('do some job'); 72 | } 73 | /* 74 | * Prototype 75 | * 76 | * @param null 77 | * @return null 78 | */ 79 | public function acmePrototype() 80 | { 81 | (new \App\Patterns\Creational\Prototype\AcmePrototype\Application)->render(); 82 | } 83 | 84 | public function staticFactory() 85 | { 86 | (new \App\Patterns\Creational\StaticFactory\Suppliers\Application)->render(); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /bootstraps/routes.php: -------------------------------------------------------------------------------- 1 | addItem(new ChickenBurger()); 18 | 19 | $this->assertInstanceOf(Item::class, $meal->first()); 20 | $meal->forget(); 21 | } 22 | /** 23 | * @depends testItemCanBeAddedToMeal 24 | */ 25 | public function testMealBuilderCanCreateVegitableBurger() 26 | { 27 | $builder = new MealBuilder; 28 | $meal = $builder->prepareVegitable(); 29 | 30 | $this->assertInstanceOf(Meal::class, $meal); 31 | $this->assertInstanceOf(VegitableBurger::class, $meal->first()); 32 | $this->assertInstanceOf(Packing::class, $meal->first()->packing()); 33 | 34 | $this->assertEquals('100.20', $meal->first()->price()); 35 | $this->assertEquals('Vegitable Burger', $meal->first()->name()); 36 | $this->assertEquals('Wrapper', $meal->first()->packing()->pack()); 37 | } 38 | /** 39 | * @depends testItemCanBeAddedToMeal 40 | */ 41 | public function testMealBuilderCanCreateNonVegitableBurger() 42 | { 43 | $builder = new MealBuilder; 44 | $meal = $builder->prepareNonVegitable(); 45 | 46 | $this->assertInstanceOf(Meal::class, $meal); 47 | $this->assertInstanceOf(ChickenBurger::class, $meal->first()); 48 | $this->assertInstanceOf(Packing::class, $meal->first()->packing()); 49 | 50 | $this->assertEquals('140.00', $meal->first()->price()); 51 | $this->assertEquals('Chicken Burger', $meal->first()->name()); 52 | $this->assertEquals('Wrapper', $meal->first()->packing()->pack()); 53 | } 54 | /** 55 | * @depends testItemCanBeAddedToMeal 56 | */ 57 | public function testMealBuilderCanCreateColdDrinks() 58 | { 59 | $builder = new MealBuilder; 60 | $meal = $builder->prepareVegitable(); 61 | 62 | $this->assertInstanceOf(Meal::class, $meal); 63 | $this->assertInstanceOf(Coke::class, $meal->last()); 64 | $this->assertInstanceOf(Packing::class, $meal->last()->packing()); 65 | 66 | $this->assertEquals('20.00', $meal->last()->price()); 67 | $this->assertEquals('Coke', $meal->last()->name()); 68 | $this->assertEquals('Bottle', $meal->last()->packing()->pack()); 69 | } 70 | } -------------------------------------------------------------------------------- /tests/DatabaseBuilderTest.php: -------------------------------------------------------------------------------- 1 | assertEquals($connection, $builder->getDB()->getConnection()); 21 | $this->assertEquals($postgresConnection, $postgresBuilder->getDB()->getConnection()); 22 | } 23 | /** 24 | * connect and disconnect 25 | * 26 | * @param void 27 | * @return void 28 | */ 29 | public function testUserCanDisconnectAndReconnectToTheDatabase() 30 | { 31 | $connection = 'mysql'; 32 | $builder = new DatabaseQueryBuilder($connection); 33 | 34 | $builder->getDB()->disconnect()->connect(); 35 | $this->assertEquals($connection, $builder->getDB()->getConnection()); 36 | } 37 | /** 38 | * can query mysql database 39 | * 40 | * @param void 41 | * @return void 42 | */ 43 | public function testUserCanQueryFroMysqlDatabase() 44 | { 45 | $connection = 'mysql'; 46 | $builder = new DatabaseQueryBuilder($connection); 47 | 48 | $query = $builder->select('users', ['user_id', 'user_name']) 49 | ->where('UserName = :userName', [':userName' => 'bsr.anwar']) 50 | ->get(); 51 | $this->assertEquals('SELECT user_id,user_name FROM `users` WHERE UserName = bsr.anwar', $query); 52 | } 53 | /** 54 | * can query postgres database 55 | * 56 | * @param void 57 | * @return void 58 | */ 59 | public function testUserCanQueryFromPostgresDatabase() 60 | { 61 | $connection = 'postgres'; 62 | $builder = new DatabaseQueryBuilder($connection); 63 | 64 | $query = $builder->select('users', ['user_id', 'user_name']) 65 | ->where('UserName = :userName', [':userName' => 'khan']) 66 | ->limit(0, 10) 67 | ->get(); 68 | $this->assertEquals('SELECT user_id,user_name FROM `users` WHERE UserName = khan LIMIT 0,10', $query); 69 | } 70 | /** 71 | * limit on records is missing 72 | * 73 | * @param void 74 | * @return void 75 | */ 76 | public function testUserCanNotUseLimitWithMysqlQuery() 77 | { 78 | $this->expectException(\BadMethodCallException::class); 79 | $connection = 'mysql'; 80 | $builder = new DatabaseQueryBuilder($connection); 81 | 82 | $builder->select('users', ['user_id', 'user_name']) 83 | ->where('UserName = :userName', [':userName' => 'khan']) 84 | ->limit(0, 10) 85 | ->get(); 86 | } 87 | } -------------------------------------------------------------------------------- /app/Patterns/Behavioral/Command/ApiScrapper/Queue.php: -------------------------------------------------------------------------------- 1 | prepare($query); 12 | $statement->bindValue(':status', AbstractApiScrapper::PENDING); 13 | $record = $statement->execute(); 14 | $row = $record->fetchArray(SQLITE3_ASSOC); 15 | return $row['pendings'] === 0; 16 | } 17 | 18 | public function add(Command $command) 19 | { 20 | $query = 'INSERT INTO commands (`command`, `status`) VALUES (:command, :status)'; 21 | $statement = self::$_db->prepare($query); 22 | $statement->bindValue(':command', \base64_encode(serialize($command))); 23 | $statement->bindValue(':status', $command->getStatus()); 24 | $statement->execute(); 25 | } 26 | 27 | public function getCommand(): Command 28 | { 29 | $query = 'SELECT * FROM commands WHERE status = :status LIMIT 1'; 30 | $statement = self::$_db->prepare($query); 31 | $statement->bindValue(':status', $this->status); 32 | $record = $statement->execute(); 33 | $record->finalize(); 34 | $row = $record->fetchArray(SQLITE3_ASSOC); 35 | $command = \unserialize(\base64_decode($row['command'])); 36 | $command->id = $row['id']; 37 | return $command; 38 | } 39 | 40 | public function completeCommand(Command $command): void 41 | { 42 | $query = 'UPDATE commands SET status = :status, command = :command WHERE id = :id'; 43 | $statement = self::$_db->prepare($query); 44 | $statement->bindValue(':status', $command->getStatus()); 45 | $statement->bindValue(':command', \base64_encode(serialize($command))); 46 | $statement->bindValue(':id', $command->getId()); 47 | $statement->execute()->finalize(); 48 | } 49 | 50 | public function work(): void 51 | { 52 | while(!$this->isEmpty()) { 53 | $command = $this->getCommand(); 54 | 55 | $command->execute(); 56 | } 57 | self::$_db->close(); 58 | } 59 | /** 60 | * change queue status 61 | * 62 | * @param int $status 63 | * @return self 64 | */ 65 | public function setStatus(int $status) 66 | { 67 | $this->status = $status; 68 | return $this; 69 | } 70 | /** 71 | * For our convenience, the Queue object is a Singleton. 72 | */ 73 | public static function get(): Queue 74 | { 75 | if (!static::$instance) { 76 | static::$instance = new Queue; 77 | static::createSqliteDb(); 78 | } 79 | 80 | return static::$instance; 81 | } 82 | /** 83 | * create sqlite database 84 | * 85 | * @param void 86 | * @return void 87 | */ 88 | private static function createSqliteDb() 89 | { 90 | self::$_db = new \Sqlite3(__DIR__ . '/commands.sqlite'); 91 | self::$_db->query(' 92 | DROP TABLE IF EXISTS commands; 93 | CREATE TABLE commands ( 94 | id INTEGER PRIMARY KEY AUTOINCREMENT, 95 | command TEXT, 96 | status INTEGER 97 | ) 98 | '); 99 | } 100 | } -------------------------------------------------------------------------------- /tests/AbstractTvFactoryTest.php: -------------------------------------------------------------------------------- 1 | splitStudlyCaseToArr('AwesomeName'); 24 | 25 | $this->assertEquals(2, count($arr)); 26 | $this->assertEquals('Awesome', $arr[0]); 27 | $this->assertEquals('Name', $arr[1]); 28 | } 29 | /** 30 | * it should return the called class name 31 | * 32 | * @param void 33 | * @return void 34 | */ 35 | public function testShouldCallTheCalledClassName() 36 | { 37 | $this->assertEquals('AbstractTvFactoryTest', $this->getCalledClassName()); 38 | } 39 | /** 40 | * test should create sony lcd tv 41 | * 42 | * @param void 43 | * @return void 44 | */ 45 | public function testShouldCreateSonyLcdTv() 46 | { 47 | $tvFactory = new TvFactory; 48 | $sonyLcd = $tvFactory->createSonyTv('lcd'); 49 | 50 | $this->assertInstanceOf(SonyLcdTv::class, $sonyLcd); 51 | $this->assertSame('added the lcd screen', $sonyLcd->addScreen()); 52 | $this->assertSame('added the power button option to turn on and off', $sonyLcd->addPowerOption()); 53 | $this->assertSame('Sony Lcd Tv is ready to be shipped', $sonyLcd->make()); 54 | } 55 | /** 56 | * test should create sony lcd tv 57 | * 58 | * @param void 59 | * @return void 60 | */ 61 | public function testShouldCreateSonyPlasmaTv() 62 | { 63 | $tvFactory = new TvFactory; 64 | $sonyPlasma = $tvFactory->createSonyTv('plasma'); 65 | 66 | $this->assertInstanceOf(SonyPlasmaTv::class, $sonyPlasma); 67 | $this->assertEquals('added the plasma screen', $sonyPlasma->addScreen()); 68 | $this->assertEquals('added the power button option to turn on and off', $sonyPlasma->addPowerOption()); 69 | $this->assertEquals('Sony Plasma Tv is ready to be shipped', $sonyPlasma->make()); 70 | } 71 | /** 72 | * test should throw error for invalid sony type 73 | * 74 | * @param void 75 | * @return void 76 | */ 77 | public function testShouldThrowErrorOnInvalidSonyType() 78 | { 79 | $this->expectException(\Exception::class); 80 | 81 | $tvFactory = new TvFactory; 82 | $tvFactory->createSonyTv('blah'); 83 | } 84 | /** 85 | * test should create huwai smart tv 86 | * 87 | * @param void 88 | * @return void 89 | */ 90 | public function testShouldCreateHuwaiSmartTv() 91 | { 92 | $tvFactory = new TvFactory; 93 | $huwaiSmart = $tvFactory->createHuwaiTv('smart'); 94 | 95 | $this->assertInstanceOf(HuwaiSmartTv::class, $huwaiSmart); 96 | $this->assertEquals('added the huwai default plastic screen', $huwaiSmart->addScreen()); 97 | $this->assertEquals('added the power button option to turn on and off and also added the voice power option to turn on and off', $huwaiSmart->addPowerOption()); 98 | $this->assertEquals('Huwai Smart Tv is ready to be shipped', $huwaiSmart->make()); 99 | } 100 | /** 101 | * test should create huwai led tv 102 | * 103 | * @param void 104 | * @return void 105 | */ 106 | public function testShouldCreateHuwaiLedTv() 107 | { 108 | $tvFactory = new TvFactory; 109 | $huwaiLed = $tvFactory->createHuwaiTv('led'); 110 | 111 | $this->assertInstanceOf(HuwaiLedTv::class, $huwaiLed); 112 | $this->assertEquals('added LED screen', $huwaiLed->addScreen()); 113 | $this->assertEquals('added the power button option to turn on and off', $huwaiLed->addPowerOption()); 114 | $this->assertEquals('Huwai Led Tv is ready to be shipped', $huwaiLed->make()); 115 | } 116 | /** 117 | * test should throw error for invalid huwai type 118 | * 119 | * @param void 120 | * @return void 121 | */ 122 | public function testShouldThrowErrorOnInvalidHuwaiType() 123 | { 124 | $this->expectException(\Exception::class); 125 | 126 | $tvFactory = new TvFactory; 127 | $tvFactory->createHuwaiTv('blah'); 128 | } 129 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Design-Patterns 2 | The intent of the repository is to inspire developers to understand and use design patterns through various examples. Please consider adding example for any pattern that may help others understand the pattern well. 3 | 4 | # Installation 5 | 6 | Please follow the guidelines in order to run this project. 7 | 8 | - Clone the repo using `git clone https://github.com/basherr/PHP-Design-Patterns.git` 9 | - Run the following command inside the cloned folder: `composer install` 10 | - Make sure all the test cases passes by running `composer test` command 11 | - To serve the project, navigate inside `public/` folder and run the command: `php -S localhost:8000` 12 | 13 | Checkout the [routes.php](https://github.com/basherr/PHP-Design-Patterns/blob/master/bootstraps/routes.php) for testing any specific pattern example. 14 | 15 | If you find some implementation wrong or vague, please create an issue and let us help each other in the path for learning **Design Patterns**. 16 | 17 | # Example Creational Design Patterns 18 | - [Abstract Pattern](https://github.com/basherr/PHP-Design-Patterns/tree/master/app/Patterns/Creational/AbstractPattern) 19 | - [Tv Manufacturer Example](https://github.com/basherr/PHP-Design-Patterns/tree/master/app/Patterns/Creational/AbstractPattern/TvManufacturer) - *Contributed by owner* 20 | - [Builder Pattern](https://github.com/basherr/PHP-Design-Patterns/tree/master/app/Patterns/Creational/Builder) 21 | - [Database](https://github.com/basherr/PHP-Design-Patterns/tree/master/app/Patterns/Creational/Builder/Database) - *Contributed by owner* 22 | - [Resturant](https://github.com/basherr/PHP-Design-Patterns/tree/master/app/Patterns/Creational/Builder/Database/Resturant) - *Contributed by owner* 23 | - [Factroy Method Pattern](https://github.com/basherr/PHP-Design-Patterns/tree/master/app/Patterns/Creational/FactoryMethod) 24 | - [Car Manufacturer](https://github.com/basherr/PHP-Design-Patterns/tree/master/app/Patterns/Creational/FactoryMethod/CarManufacturer) - *Contributed by owner* 25 | - [Logger](https://github.com/basherr/PHP-Design-Patterns/tree/master/app/Patterns/Creational/FactoryMethod/Logger) - *Contributed by owner* 26 | - [Pool Pattern](https://github.com/basherr/PHP-Design-Patterns/tree/master/app/Patterns/Creational/Pool) 27 | - [StringReverse Worker](https://github.com/basherr/PHP-Design-Patterns/tree/master/app/Patterns/Creational/Pool/Worker) - *Contributed by owner* 28 | - [Prototype Pattern](https://github.com/basherr/PHP-Design-Patterns/tree/master/app/Patterns/Creational/Prototype) 29 | - [AcmePrototype](https://github.com/basherr/PHP-Design-Patterns/tree/master/app/Patterns/Creational/Prototype/AcmePrototype) - *Contributed by owner* 30 | - [Static Factory Pattern](https://github.com/basherr/PHP-Design-Patterns/tree/master/app/Patterns/Creational/StaticFactory) 31 | - [Suppliers](https://github.com/basherr/PHP-Design-Patterns/tree/master/app/Patterns/Creational/StaticFactory/Suppliers) - *Contributed by owner* 32 | 33 | # Example Structural Design Patterns 34 | - [Adapter Pattern](https://github.com/basherr/PHP-Design-Patterns/tree/master/app/Patterns/Structural/AdapterPattern) 35 | - [Human Adapter](https://github.com/basherr/PHP-Design-Patterns/tree/master/app/Patterns/Structural/AdapterPattern/Human) - *Contributed by owner* 36 | - [Operating Systems Adapter](https://github.com/basherr/PHP-Design-Patterns/tree/master/app/Patterns/Structural/AdapterPattern/OperatingSystems) - *Contributed by owner* 37 | - [Bridge Pattern](https://github.com/basherr/PHP-Design-Patterns/tree/master/app/Patterns/Structural/BridgePattern) 38 | - [Flight Supplier Bridge](https://github.com/basherr/PHP-Design-Patterns/tree/master/app/Patterns/Structural/BridgePattern/FlightApi) - *Contributed by owner* 39 | - [Composite Pattern](https://github.com/basherr/PHP-Design-Patterns/tree/master/app/Patterns/Structural/CompositePattern) 40 | - [Composite Form](https://github.com/basherr/PHP-Design-Patterns/tree/master/app/Patterns/Structural/CompositePattern/Form) - *Contributed by owner* 41 | - [Decorator Pattern](https://github.com/basherr/PHP-Design-Patterns/tree/master/app/Patterns/Structural/DecoratorPattern) 42 | - [Active Record](https://github.com/basherr/PHP-Design-Patterns/tree/master/app/Patterns/Structural/DecoratorPattern/ActiveRecord) - *Contributed by owner* 43 | - [Facade](https://github.com/basherr/PHP-Design-Patterns/tree/master/app/Patterns/Structural/Facade) 44 | - [Quickbooks](https://github.com/basherr/PHP-Design-Patterns/tree/master/app/Patterns/Structural/Facade/Quickbooks) - *Contributed by owner* 45 | - [Proxy Pattern](https://github.com/basherr/PHP-Design-Patterns/tree/master/app/Patterns/Structural/ProxyPattern) 46 | - [File Reader Proxy](https://github.com/basherr/PHP-Design-Patterns/tree/master/app/Patterns/Structural/ProxyPattern/FileReader) - *Contributed by owner* 47 | - [Registery Pattern](https://github.com/basherr/PHP-Design-Patterns/tree/master/app/Patterns/Structural/RegisteryPattern) 48 | - [Exam Registery](https://github.com/basherr/PHP-Design-Patterns/tree/master/app/Patterns/Structural/RegisteryPattern/Exam) - *Contributed by owner* 49 | - [Dependency Injection Pattern](https://github.com/basherr/PHP-Design-Patterns/tree/master/app/Patterns/Structural/DependencyInjectionPattern) 50 | - [Mailer](https://github.com/basherr/PHP-Design-Patterns/tree/master/app/Patterns/Structural/DependencyInjectionPattern/Mailer) - *Contributed by owner* 51 | 52 | # Example Behavior Design Patterns 53 | - [Chain Of Responsibility Pattern](https://github.com/basherr/PHP-Design-Patterns/tree/master/app/Patterns/Behavioral/ChainOfResponsibility) 54 | - [Handle Http Request](https://github.com/basherr/PHP-Design-Patterns/tree/master/app/Patterns/Behavioral/ChainOfResponsibility/HandleHttpRequests) - *Contributed by owner* 55 | - [Command Pattern](https://github.com/basherr/PHP-Design-Patterns/tree/master/app/Patterns/Behavioral/Command/) 56 | - [API Scrapper](https://github.com/basherr/PHP-Design-Patterns/tree/master/app/Patterns/Behavioral/Command/ApiScrapper) - *Contributed by owner* 57 | - [Iterator Pattern](https://github.com/basherr/PHP-Design-Patterns/tree/master/app/Patterns/Behavioral/Iterator) 58 | - [Hotel Suppliers](https://github.com/basherr/PHP-Design-Patterns/tree/master/app/Patterns/Behavioral/Iterator/HotelSuppliers) - *Contributed by owner* 59 | - [Observer Pattern](https://github.com/basherr/PHP-Design-Patterns/tree/master/app/Patterns/Behavioral/Observer) 60 | - [User Signup Observer](https://github.com/basherr/PHP-Design-Patterns/tree/master/app/Patterns/Behavioral/Observer/NewUserSignedup) - *Contributed by owner* 61 | 62 | 63 | # Contribution-Guides 64 | Your contribution may have a very good impact on the community thus try sharing every possible example that you can either think of or had experienced in the past. 65 | 66 | The repository is not based on any framework but rather inspired by [No Framework](https://github.com/PatrickLouys/no-framework-tutorial) 67 | 68 | The code structure for the repository is as follows: 69 | - `app` 70 | - `bootstraps` 71 | - `public` 72 | - `stubs` 73 | - `tests` 74 | 75 | The life cycle of the application is as follows: 76 | 77 | - `public/index.php` serves as the entry point for the entire application which loads `boostrap/autoload.php` 78 | - `bootstrap/autoload.php` processes `HTTP` request and forwards the route to the relevant `Controller method` defined in `bootstrap/routes.php`. 79 | 80 | In order to contribute and add real world example for the related pattern, please follow the guidelines: 81 | - Fork the repository 82 | - Create a folder inside `app/Patterns/{Type e.g Creational, Behavioral or Structural}/{Pattern Name}/{Example Name}/your code` 83 | - Please create a READMe.md and include a UML diagram. [Example README.md](https://github.com/basherr/PHP-Design-Patterns/tree/master/app/Patterns/Creational/AbstractPattern/TvManufacturer) 84 | - Add `unit tests` 85 | - Create `Application.php` with a method named `render` to describe the usage. [Example Application.php](https://github.com/basherr/PHP-Design-Patterns/blob/master/app/Patterns/Creational/AbstractPattern/TvManufacturer/Application.php) 86 | - Add a method in the relevant controller(e.g creational) and add a route in `bootstraps/routes.php` 87 | - Please run `composer test` and make sure all tests are passing 88 | - Create a PR against the master branch 89 | 90 | Please feel free to contribute and create pull requests. 91 | 92 | # Console Commands 93 | The only console command available for creating tests is: 94 | 95 | `php .\bootstraps\console_autoload.php MyAwesomeTestName` 96 | 97 | # Discussions 98 | 99 | Please create an issue or join [Discord](https://discord.gg/G89qtfGR) for any discussion. 100 | 101 | # Licenese 102 | All of the codebases are **MIT licensed** unless otherwise specified. 103 | --------------------------------------------------------------------------------