This commit is contained in:
Yevhen Odynets 2025-07-03 23:46:08 +03:00
parent 7fe2402ff3
commit ab4499a305
39 changed files with 453 additions and 56 deletions

62
code/adapter.php Normal file
View File

@ -0,0 +1,62 @@
<?php
/**
* @package: patterns
* @author: Yevhen Odynets
* @date: 2025-07-03
* @time: 21:21
*/
declare(strict_types = 1);
use Pattern\Structural\Adapter\JsonReport;
use Pattern\Structural\Adapter\JsonToPHPArrayReportAdapter;
use Pattern\Structural\Adapter\PHPArrayReport;
use Pattern\Structural\Adapter\PHPArrayReportInterfaceAdapter;
use Pattern\Structural\Adapter\SerializedReport;
use Pattern\Structural\Adapter\SerializedToPHPArrayReportAdapter;
use Pattern\Structural\Adapter\XMLReport;
use Pattern\Structural\Adapter\XMLToPHPArrayReportAdapter;
use Pattern\Structural\Adapter\YamlReport;
use Pattern\Structural\Adapter\YamlToPHPArrayReportAdapter;
$reports = [
// new YamlReport(),
new PHPArrayReport(),
new XMLReport(),
new SerializedReport(),
new JsonReport(),
];
function client(array $reports): void
{
foreach ($reports as $report) {
$adapter = null;
if ($report instanceof PHPArrayReport) {
$adapter = $report;
} elseif ($report instanceof JsonReport) {
$adapter = new JsonToPHPArrayReportAdapter($report);
} elseif ($report instanceof SerializedReport) {
$adapter = new SerializedToPHPArrayReportAdapter($report);
} elseif ($report instanceof XMLReport) {
$adapter = new XMLToPHPArrayReportAdapter($report);
} elseif ($report instanceof YamlReport) {
$adapter = new YamlToPHPArrayReportAdapter($report);
}
if (! is_null($adapter)) {
echo $adapter::class;
renderView($adapter);
}
}
}
function renderView(PHPArrayReportInterfaceAdapter $adapter): void
{
/** @noinspection ForgottenDebugOutputInspection */
dump($adapter->getData());
}
?><img class="diagram" src="/assets/img/diagrams/adapter.png" alt="Adapter DEsign Pattern Diagram"><?php
client($reports);

View File

@ -1,24 +1,26 @@
{ {
"name": "the-amok/patterns", "name": "the-amok/patterns",
"autoload": { "autoload": {
"psr-4": { "psr-4": {
"": "src/" "": "src/"
}
},
"authors": [
{
"name": "Yevhen Odynets",
"email": "dev@amok.space"
}
],
"require": {
"php": "8.3.*"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.76"
},
"scripts": {
"cs": "php-cs-fixer --config=./.php-cs-fixer.php check -v",
"cs:fix": "php-cs-fixer --config=./.php-cs-fixer.php fix -v"
} }
},
"authors": [
{
"name": "Yevhen Odynets",
"email": "dev@amok.space"
}
],
"require": {
"php": "8.3.*",
"ext-simplexml": "*",
"ext-yaml": "*"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.76"
},
"scripts": {
"cs": "php-cs-fixer --config=./.php-cs-fixer.php check -v",
"cs:fix": "php-cs-fixer --config=./.php-cs-fixer.php fix -v"
}
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

View File

@ -9,9 +9,9 @@ require '../src/helpers.php';
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge"> <meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Патерни</title> <title>Патерни</title>
<link rel="stylesheet" href="assets/css/agate.min.css"> <link rel="stylesheet" href="/assets/css/agate.min.css">
<script src="assets/js/highlight.min.js"></script> <script src="/assets/js/highlight.min.js"></script>
<script src="assets/js/stylus.min.js"></script> <script src="/assets/js/stylus.min.js"></script>
<style> <style>
html, body { html, body {
position: relative; position: relative;
@ -25,6 +25,7 @@ require '../src/helpers.php';
} }
main { main {
box-sizing: border-box;
box-shadow: -1px 1px 5px 0 rgba(123, 123, 123, 1); box-shadow: -1px 1px 5px 0 rgba(123, 123, 123, 1);
-webkit-box-shadow: -1px 1px 5px 0 rgba(123, 123, 123, 1); -webkit-box-shadow: -1px 1px 5px 0 rgba(123, 123, 123, 1);
-moz-box-shadow: -1px 1px 5px 0 rgba(123, 123, 123, 1); -moz-box-shadow: -1px 1px 5px 0 rgba(123, 123, 123, 1);
@ -37,24 +38,23 @@ require '../src/helpers.php';
top: 50%; top: 50%;
left: 50%; left: 50%;
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
max-height: 92dvh;
overflow-y: auto;
} }
pre { pre {
font-family: Consolas, monospace; font-family: Consolas, monospace;
align-self: center; align-self: center;
}
img.diagram {
max-width: 100%;
} }
</style> </style>
</head> </head>
<body> <body>
<main> <main>
<?php <?php require '../src/router.php' ?>
/** Creational patterns **/
// require '../code/singleton.php';
// require '../code/factory_method.php';
require '../code/abstract_factory.php';
?>
</main> </main>
<script>hljs.highlightAll()</script> <script>hljs.highlightAll()</script>
</body> </body>

View File

@ -22,4 +22,4 @@ interface AbstractFactoryInterface
* @return PackageInterface * @return PackageInterface
*/ */
public function createPackage(): PackageInterface; public function createPackage(): PackageInterface;
} }

View File

@ -14,4 +14,4 @@ namespace Pattern\Creational\AbstractFactory;
interface DeliveryServiceInterface interface DeliveryServiceInterface
{ {
public function sendPackage(PackageInterface $package): void; public function sendPackage(PackageInterface $package): void;
} }

View File

@ -18,4 +18,4 @@ class JustinDeliveryService implements DeliveryServiceInterface
/** @noinspection ForgottenDebugOutputInspection */ /** @noinspection ForgottenDebugOutputInspection */
dump("Sending package via Justin..."); dump("Sending package via Justin...");
} }
} }

View File

@ -18,4 +18,4 @@ class JustinPackage implements PackageInterface
/** @noinspection ForgottenDebugOutputInspection */ /** @noinspection ForgottenDebugOutputInspection */
dump('Checking package from Justin...'); dump('Checking package from Justin...');
} }
} }

View File

@ -19,4 +19,4 @@ class MeestDeliveryService implements DeliveryServiceInterface
/** @noinspection ForgottenDebugOutputInspection */ /** @noinspection ForgottenDebugOutputInspection */
dump("Sending package via Meest..."); dump("Sending package via Meest...");
} }
} }

View File

@ -18,4 +18,4 @@ class MeestPackage implements PackageInterface
/** @noinspection ForgottenDebugOutputInspection */ /** @noinspection ForgottenDebugOutputInspection */
dump('Checking package from Meest...'); dump('Checking package from Meest...');
} }
} }

View File

@ -18,4 +18,4 @@ class NovapostDeliveryService implements DeliveryServiceInterface
/** @noinspection ForgottenDebugOutputInspection */ /** @noinspection ForgottenDebugOutputInspection */
dump("Sending package via Novapost..."); dump("Sending package via Novapost...");
} }
} }

View File

@ -18,4 +18,4 @@ class NovapostPackage implements PackageInterface
/** @noinspection ForgottenDebugOutputInspection */ /** @noinspection ForgottenDebugOutputInspection */
dump('Checking package from Novapost...'); dump('Checking package from Novapost...');
} }
} }

View File

@ -14,4 +14,4 @@ namespace Pattern\Creational\AbstractFactory;
interface PackageInterface interface PackageInterface
{ {
public function getConsist(): void; public function getConsist(): void;
} }

View File

@ -18,4 +18,4 @@ class UkrpostDeliveryService implements DeliveryServiceInterface
/** @noinspection ForgottenDebugOutputInspection */ /** @noinspection ForgottenDebugOutputInspection */
dump("Sending package via Ukrpost..."); dump("Sending package via Ukrpost...");
} }
} }

View File

@ -18,4 +18,4 @@ class UkrpostPackage implements PackageInterface
/** @noinspection ForgottenDebugOutputInspection */ /** @noinspection ForgottenDebugOutputInspection */
dump('Checking package from Ukrpost...'); dump('Checking package from Ukrpost...');
} }
} }

View File

@ -18,4 +18,4 @@ class CashPayment implements PaymentInterface
/** @noinspection ForgottenDebugOutputInspection */ /** @noinspection ForgottenDebugOutputInspection */
dump("Cash payment success, amount: {$order->getSum()}"); dump("Cash payment success, amount: {$order->getSum()}");
} }
} }

View File

@ -18,4 +18,4 @@ class IngPayment implements PaymentInterface
/** @noinspection ForgottenDebugOutputInspection */ /** @noinspection ForgottenDebugOutputInspection */
dump("ING Bank payment success, amount: {$order->getSum()}"); dump("ING Bank payment success, amount: {$order->getSum()}");
} }
} }

View File

@ -17,4 +17,4 @@ class IngPaymentFactory implements PaymentFactoryInterface
{ {
return new IngPayment(); return new IngPayment();
} }
} }

View File

@ -18,4 +18,4 @@ class OtpPayment implements PaymentInterface
/** @noinspection ForgottenDebugOutputInspection */ /** @noinspection ForgottenDebugOutputInspection */
dump("Otp Bank payment success, amount: {$order->getSum()}"); dump("Otp Bank payment success, amount: {$order->getSum()}");
} }
} }

View File

@ -17,4 +17,4 @@ class OtpPaymentFactory implements PaymentFactoryInterface
{ {
return new OtpPayment(); return new OtpPayment();
} }
} }

View File

@ -14,4 +14,4 @@ namespace Pattern\Creational\FactoryMethod;
interface PaymentInterface interface PaymentInterface
{ {
public function pay(Order $order): void; public function pay(Order $order): void;
} }

View File

@ -18,4 +18,4 @@ class PrivatPayment implements PaymentInterface
/** @noinspection ForgottenDebugOutputInspection */ /** @noinspection ForgottenDebugOutputInspection */
dump("Privatbank payment success, amount: {$order->getSum()}"); dump("Privatbank payment success, amount: {$order->getSum()}");
} }
} }

View File

@ -18,4 +18,4 @@ class RaiffeisenPayment implements PaymentInterface
/** @noinspection ForgottenDebugOutputInspection */ /** @noinspection ForgottenDebugOutputInspection */
dump("Raiffeisen Bank payment success, amount: {$order->getSum()}"); dump("Raiffeisen Bank payment success, amount: {$order->getSum()}");
} }
} }

View File

@ -17,4 +17,4 @@ class RaiffeisenPaymentFactory implements PaymentFactoryInterface
{ {
return new RaiffeisenPayment(); return new RaiffeisenPayment();
} }
} }

View File

@ -14,4 +14,4 @@ namespace Pattern\Creational\Singleton;
interface Loggable interface Loggable
{ {
public static function getInstance(): static; public static function getInstance(): static;
} }

View File

@ -9,6 +9,7 @@
//phpcs:ignore //phpcs:ignore
declare(strict_types = 1); declare(strict_types = 1);
namespace Pattern\Creational\Singleton; namespace Pattern\Creational\Singleton;
class Single extends Singleton implements SingleInterface class Single extends Singleton implements SingleInterface
@ -18,4 +19,4 @@ class Single extends Singleton implements SingleInterface
/** @noinspection ForgottenDebugOutputInspection */ /** @noinspection ForgottenDebugOutputInspection */
dump(__METHOD__); dump(__METHOD__);
} }
} }

View File

@ -101,5 +101,3 @@ class Singleton
return $this; return $this;
} }
} }

View File

@ -0,0 +1,46 @@
<?php
/**
* @package: patterns
* @author: Yevhen Odynets
* @date: 2025-07-03
* @time: 21:59
*/
declare(strict_types = 1);
namespace Pattern\Structural\Adapter;
use JsonException;
class JsonReport
{
/**
* @throws JsonException
*/
public function buildJson(): string
{
return json_encode([
[
'name' => 'Mikrotik RB4011iGS+RM',
'price' => 9094,
'count' => 27,
],
[
'name' => 'Cisco ISR4331-VSEC/K9',
'price' => 167955,
'count' => 8,
],
[
'name' => 'TP-Link ER605 (TL-R605)',
'price' => 2499,
'count' => 895,
],
[
'name' => 'D-Link DSL-2500U/BRU/D',
'price' => 420,
'count' => 112,
],
], JSON_THROW_ON_ERROR | JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
}
}

View File

@ -0,0 +1,30 @@
<?php
/**
* @package: patterns
* @author: Yevhen Odynets
* @date: 2025-07-03
* @time: 22:38
*/
declare(strict_types = 1);
namespace Pattern\Structural\Adapter;
use JsonException;
final readonly class JsonToPHPArrayReportAdapter implements PHPArrayReportInterfaceAdapter
{
public function __construct(private JsonReport $report) {}
/**
* @throws JsonException
*/
public function getData(): array
{
$data = $this->report->buildJson();
return json_decode($data, true, 512, JSON_THROW_ON_ERROR);
}
}

View File

@ -0,0 +1,36 @@
<?php
/**
* @package: patterns
* @author: Yevhen Odynets
* @date: 2025-07-03
* @time: 21:47
*/
declare(strict_types = 1);
namespace Pattern\Structural\Adapter;
class PHPArrayReport implements PHPArrayReportInterfaceAdapter
{
public function getData(): array
{
return [
[
'name' => 'USB HDD Transcend StoreJet25M3 2 TB Iron Gray (TS2TSJ25M3S)',
'price' => 4589,
'count' => 536,
],
[
'name' => 'HDD Seagate IronWolf 4 TB (ST4000VN006)',
'price' => 5069,
'count' => 346,
],
[
'name' => 'HDD WD Purple 4 TB (WD43PURZ)',
'price' => 4109,
'count' => 142,
],
];
}
}

View File

@ -0,0 +1,17 @@
<?php
/**
* @package: patterns
* @author: Yevhen Odynets
* @date: 2025-07-03
* @time: 22:37
*/
declare(strict_types = 1);
namespace Pattern\Structural\Adapter;
interface PHPArrayReportInterfaceAdapter
{
public function getData(): array;
}

View File

@ -0,0 +1,46 @@
<?php
/**
* @package: patterns
* @author: Yevhen Odynets
* @date: 2025-07-03
* @time: 22:07
*/
declare(strict_types = 1);
namespace Pattern\Structural\Adapter;
class SerializedReport
{
public function getData(): string
{
return serialize([
[
'name' => 'Makita 4329',
'price' => 3479,
'count' => 395,
],
[
'name' => 'Bosch PST 650 (06033A0721)',
'price' => 2103,
'count' => 983,
],
[
'name' => 'Dnipro-M JS-65LX (98609000)',
'price' => 1920,
'count' => 674,
],
[
'name' => 'RZTK AJ 650 (252143876)',
'price' => 699,
'count' => 1265,
],
[
'name' => 'AEG STEP 70 (4935412900)',
'price' => 3950,
'count' => 765,
],
]);
}
}

View File

@ -0,0 +1,23 @@
<?php
/**
* @package: patterns
* @author: Yevhen Odynets
* @date: 2025-07-03
* @time: 22:38
*/
declare(strict_types = 1);
namespace Pattern\Structural\Adapter;
final readonly class SerializedToPHPArrayReportAdapter implements PHPArrayReportInterfaceAdapter
{
public function __construct(private SerializedReport $report) {}
public function getData(): array
{
return unserialize($this->report->getData(), ["allowed_classes" => false]);
}
}

View File

@ -0,0 +1,37 @@
<?php
/**
* @package: patterns
* @author: Yevhen Odynets
* @date: 2025-07-03
* @time: 22:26
*/
declare(strict_types = 1);
namespace Pattern\Structural\Adapter;
class XMLReport
{
public function buildXML(): string
{
return '<?xml version="1.0" encoding="UTF-8"?>
<root>
<element0>
<name>Ibanez RG421EX</name>
<price>21278</price>
<count>129</count>
</element0>
<element1>
<name>Fender Debut Stratocaster HSS Dakota Red</name>
<price>8400</price>
<count>289</count>
</element1>
<element2>
<name>Harley Benton ST-20 BK Standard Series</name>
<price>5190</price>
<count>389</count>
</element2>
</root>';
}
}

View File

@ -0,0 +1,32 @@
<?php
/**
* @package: patterns
* @author: Yevhen Odynets
* @date: 2025-07-03
* @time: 22:38
*/
declare(strict_types = 1);
namespace Pattern\Structural\Adapter;
use JsonException;
final readonly class XMLToPHPArrayReportAdapter implements PHPArrayReportInterfaceAdapter
{
public function __construct(private XMLReport $report) {}
/**
* @throws JsonException
*/
public function getData(): array
{
$xmlData = $this->report->buildXML();
$xml = simplexml_load_string($xmlData);
$json = json_encode($xml, JSON_THROW_ON_ERROR);
return json_decode($json, true, 512, JSON_THROW_ON_ERROR);
}
}

View File

@ -0,0 +1,28 @@
<?php
/**
* @package: patterns
* @author: Yevhen Odynets
* @date: 2025-07-03
* @time: 21:59
*/
declare(strict_types = 1);
namespace Pattern\Structural\Adapter;
use JsonException;
class YamlReport
{
public function emitYaml(): string
{
return yaml_emit([
[
'name' => 'Apple iPhone 16 Pro Max 256GB Natural Titanium (MYWY3)',
'price' => 62799,
'count' => 2127,
]
], YAML_UTF8_ENCODING);
}
}

View File

@ -0,0 +1,23 @@
<?php
/**
* @package: patterns
* @author: Yevhen Odynets
* @date: 2025-07-03
* @time: 22:38
*/
declare(strict_types = 1);
namespace Pattern\Structural\Adapter;
final readonly class YamlToPHPArrayReportAdapter implements PHPArrayReportInterfaceAdapter
{
public function __construct(private YamlReport $report) {}
public function getData(): array
{
return yaml_parse($this->report->emitYaml());
}
}

View File

@ -41,4 +41,4 @@ function trace(): string
function getFloatRange(): float function getFloatRange(): float
{ {
return (float)random_int(1000, 999999) / 100; return (float)random_int(1000, 999999) / 100;
} }

16
src/router.php Normal file
View File

@ -0,0 +1,16 @@
<?php
/**
* @package: patterns
* @author: Yevhen Odynets
* @date: 2025-07-03
* @time: 21:26
*/
declare(strict_types = 1);
preg_match('/^\/patterns\/([a-z0-9-]+)/', $_SERVER["REQUEST_URI"], $patterns);
if (isset($patterns[1]) && file_exists('../code/' . $patterns[1] . '.php')) {
require '../code/' . $patterns[1] . '.php';
}