gang of four

main
Robert 1 month ago
parent a9995970f3
commit f89f6ae772
  1. BIN
      docs/Gang_of_Four_Design_Patterns.pdf
  2. 3
      docs/Notes.txt
  3. 62
      docs/OOP_Design_Patterns.html
  4. 8
      docs/TODO.md
  5. 2
      src/bootstrap/errors.php
  6. 23
      src/bootstrap/main.php
  7. 2
      src/classes/common.php
  8. 154
      src/classes/services/Logger.php
  9. 8
      src/classes/view.php

@ -0,0 +1,3 @@
About Data Transfer Objects, etc...:
https://chatgpt.com/share/6956d98b-3d5c-8001-8139-a8598747b111

@ -0,0 +1,62 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Gang of Four Design Patterns</title>
</head>
<body>
<h1>23 Classic Gang of Four Design Patterns</h1>
<p style="font-size: small;">Generated by ChatGPT:</p>
<h2>Creational Patterns (deal with object creation)</h2>
<ol>
<li><strong>Singleton</strong> - Ensures a class has only one instance and provides a global point of access to it.</li>
<li><strong>Factory Method</strong> - Defines an interface for creating objects but lets subclasses decide which class to instantiate.</li>
<li><strong>Abstract Factory</strong> - Provides an interface for creating families of related objects without specifying their concrete classes.</li>
<li><strong>Builder</strong> - Separates the construction of a complex object from its representation, allowing the same construction process to create different representations.</li>
<li><strong>Prototype</strong> - Creates new objects by copying an existing object (prototype) rather than creating from scratch.</li>
</ol>
<h2>Structural Patterns (deal with object composition)</h2>
<ol start="6">
<li><strong>Adapter</strong> - Converts the interface of one class into another interface that clients expect, enabling incompatible classes to work together.</li>
<li><strong>Bridge</strong> - Decouples an abstraction from its implementation so they can vary independently, preventing a permanent binding between them.</li>
<li><strong>Composite</strong> - Composes objects into tree structures to represent part-whole hierarchies, letting clients treat individual objects and compositions uniformly.</li>
<li><strong>Decorator</strong> - Attaches additional responsibilities to an object dynamically, providing a flexible alternative to subclassing for extending functionality.</li>
<li><strong>Facade</strong> - Provides a unified, simplified interface to a complex subsystem, making it easier to use.</li>
<li><strong>Flyweight</strong> - Minimizes memory usage by sharing as much data as possible with similar objects; used when large numbers of objects are needed.</li>
<li><strong>Proxy</strong> - Provides a surrogate or placeholder for another object to control access to it, useful for lazy initialization, access control, or logging.</li>
</ol>
<h2>Behavioral Patterns (deal with object interaction and responsibility)</h2>
<ol start="13">
<li><strong>Chain of Responsibility</strong> - Passes a request along a chain of handlers, where each handler decides either to process the request or pass it to the next handler.</li>
<li><strong>Command</strong> - Encapsulates a request as an object, thereby allowing parameterization of clients with different requests and supporting undoable operations.</li>
<li><strong>Interpreter</strong> - Defines a grammatical representation for a language and an interpreter to evaluate sentences in that language.</li>
<li><strong>Iterator</strong> - Provides a way to access elements of an aggregate object sequentially without exposing its underlying representation.</li>
<li><strong>Mediator</strong> - Defines an object that encapsulates how a set of objects interact, promoting loose coupling by preventing objects from referring to each other explicitly.</li>
<li><strong>Memento</strong> - Captures and externalizes an object's internal state without violating encapsulation, so the object can be restored to this state later.</li>
<li><strong>Observer</strong> - Defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.</li>
<li><strong>State</strong> - Allows an object to alter its behavior when its internal state changes, appearing to change its class.</li>
<li><strong>Strategy</strong> - Defines a family of algorithms, encapsulates each one, and makes them interchangeable, letting the algorithm vary independently from clients.</li>
<li><strong>Template Method</strong> - Defines the skeleton of an algorithm in a method, deferring some steps to subclasses, letting subclasses redefine certain steps without changing the algorithm's structure.</li>
<li><strong>Visitor</strong> - Represents an operation to be performed on elements of an object structure, letting you define new operations without changing the classes of the elements.</li>
</ol>
<p>These patterns provide proven solutions to common software design problems, promoting code reuse, flexibility, and maintainability in object-oriented systems.</p>
<h2>Links to more external resources not mine...</h2>
<blockquote style="position: relative; font-style: italic; margin: 10px 0 0; padding: 10px 12px; border-left: 3px solid #60a5fa; border-radius: 10px;">
<p>I'm not affiliated with nor profit from these Books, they are just here for your and my convenience.</p>
<p>Modern PHP 8 Design Patterns Online Version: <a href="https://designpatternsphp.readthedocs.io/en/latest/">https://designpatternsphp.readthedocs.io/en/latest/</a></p>
<p>PDF Version: <a href="https://designpatternsphp.readthedocs.io/_/downloads/en/latest/pdf/">https://designpatternsphp.readthedocs.io/_/downloads/en/latest/pdf/</a></p>
<p>Nice Book for sale: Buy Dive Into DESIGN PATTERNS An Ebook on design patterns and the principles behind them: <a href="https://refactoring.guru/design-patterns/book">https://refactoring.guru/design-patterns/book</a></p>
<p>PHP Code from the Book above: <a href="https://refactoring.guru/design-patterns/php">https://refactoring.guru/design-patterns/php</a>, If you liked it; Please support them by buying the book above...</p>
<p>"The Gang of 4 book" - Design Patterns: Elements of Reusable Object-Oriented Software By Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides, Published Oct 31, 1994. Buy here it: <a href="https://www.informit.com/store/design-patterns-elements-of-reusable-object-oriented-9780201633610">https://www.informit.com/store/design-patterns-elements-of-reusable-object-oriented-9780201633610</a></p>
<p><a href="https://www.informit.com/imprint/series_detail.aspx?st=61147">More on The Addison-Wesley Professional Computing Series</a></p>
</blockquote>
</body>
</html>

@ -34,7 +34,13 @@
- [ ] → Sane Config/Service file defaults - [ ] → Sane Config/Service file defaults
- [ ] → Sane Folder Structure and Documentation - [ ] → Sane Folder Structure and Documentation
- [x] → Default Routes, then load Controllers - [x] → Default Routes, then load Controllers
- [ ] → composer require psr/http-message
- [ ] → PSR Xx Compliant Standards...
- [ ] → class InvoiceException extends \Exception{ public static function missingBillingInfo(): static { return new static('Missing billing info'); } }
- [ ] → view __toString(): string{return $ this->render();}
- [ ] → view __get(string $name) {return $this->params[$name] ?? null;}
- [ ] → flash session messages
- [ ] → https://www.youtube.com/watch?v=iCKzIIE4w5E&list=PLr3d3QYzkw2xabQRUpcZ_IBk9W50M9pe-&index=66
## Extras: ## Extras:
- [x] → LazyCollections, LazyObjects, Money Class - [x] → LazyCollections, LazyObjects, Money Class
- [ ] → Tests - [ ] → Tests

@ -145,7 +145,7 @@ function formatMessage($message, $type = 'error') {
} }
// Custom error handler // Custom error handler
set_error_handler(function($errno, $errstr, $errfile, $errline) { set_error_handler(function(int $errno, string $errstr, ?string $errfile, ?int $errline) {
// Skip if error reporting is turned off // Skip if error reporting is turned off
if (!(error_reporting() & $errno)) { if (!(error_reporting() & $errno)) {
return false; return false;

@ -64,9 +64,10 @@ final class configure {
private static $config = []; private static $config = [];
protected function __construct() { private function __construct(){}
private function __clone(){}
} private function __wakeup(){}
private function __destruct(){}
public static function exists() { // an Alias to has public static function exists() { // an Alias to has
return self::has(func_get_args()); return self::has(func_get_args());
@ -195,9 +196,15 @@ final class di {
...$more ...$more
) { ) {
if ($this->has($service_name) ) { if ($this->has($service_name) ) {
return $this->services[$service_name]($args, $more); $entry = $this->services[$service_name];
if (is_callable($entry)) {
return $entry($args, $more);
} }
return $this->resolve($service_name); // Try to Auto-Wire
$service_name = $entry;
}
return $this->resolve(c); // Try to Auto-Wire
} }
public function get_auto(string $service_name) { public function get_auto(string $service_name) {
@ -222,7 +229,7 @@ final class di {
public function list_services_as_string(): string { public function list_services_as_string(): string {
return implode(',', array_keys($this->services)); return implode(',', array_keys($this->services));
} }
// Reflection API Autowiring FROM-> https://www.youtube.com/watch?v=78Vpg97rQwE&list=PLr3d3QYzkw2xabQRUpcZ_IBk9W50M9pe-&index=72
public function resolve(string $service_name) { public function resolve(string $service_name) {
try { try {
$reflection_class = new \ReflectionClass($service_name); $reflection_class = new \ReflectionClass($service_name);
@ -247,7 +254,7 @@ final class di {
return new $service_name; return new $service_name;
} }
$dependencies = array_map( $dependencies = array_map(
function(\ReflectionParameter $param) { function(\ReflectionParameter $param) use ($service_name) {
$name = $param->getName(); $name = $param->getName();
$type = $param->getType(); $type = $param->getType();
if (! $type) { if (! $type) {
@ -282,6 +289,8 @@ registry::get('loader')->add_namespace("Project", CodeHydrater_PROJECT);
load_all::init(CodeHydrater_PROJECT); load_all::init(CodeHydrater_PROJECT);
//site_helper::load_file(CodeHydrater_FRAMEWORK . 'vendor/autoload.php');
// Keep these blocks of code here not anywhere before it... // Keep these blocks of code here not anywhere before it...
if (! defined('ENVIRONMENT')) { if (! defined('ENVIRONMENT')) {
if (is_live() === false) { if (is_live() === false) {

@ -150,7 +150,7 @@ final class common {
return F::stripos($string, $needle, $offset); return F::stripos($string, $needle, $offset);
} }
public static function string_sub_part(string $string, int $offset = 0, int $length = null, $encoding = null) { public static function string_sub_part(string $string, int $offset = 0, ?int $length = null, $encoding = null) {
if ($length === null) { if ($length === null) {
return F::substr($string, $offset, strlen($string)); return F::substr($string, $offset, strlen($string));
} else { } else {

@ -0,0 +1,154 @@
<?php
declare(strict_types=1);
namespace App\Log;
use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel;
use Psr\Log\InvalidArgumentException;
final class Logger implements LoggerInterface
{
private $handle = false;
public function __construct(
string $filename = 'system',
int $maxCount = 1000
) {
if (str_contains($filename, '..')) {
return;
}
$logDir = BaseDir . '/protected/logs';
if (!is_dir($logDir)) {
mkdir($logDir, 0775, true);
}
$filename = preg_replace('/[^A-Za-z0-9_]/', '', $filename);
$file = $logDir . '/' . $filename . '.log.txt';
if ($maxCount > 1 && $this->getLines($file) > $maxCount) {
@unlink($file);
}
if (file_put_contents($file, "\n", FILE_APPEND) === false) {
return;
}
@chmod($file, 0660);
@chgrp($file, 'www-data');
if (!is_writable($file)) {
return;
}
$this->handle = fopen($file, 'ab');
}
/* ---------------- PSR-3 Core ---------------- */
public function log($level, $message, array $context = []): void
{
if (!is_string($level)) {
throw new InvalidArgumentException('Log level must be a string');
}
if (!$this->handle || !is_resource($this->handle)) {
return;
}
$message = $this->interpolate((string)$message, $context);
$time = (new \DateTimeImmutable())->format('Y-m-d H:i:s');
fwrite(
$this->handle,
sprintf("[%s] %s: %s\n", $time, strtoupper($level), $message)
);
}
/* ---------------- Level Methods ---------------- */
public function emergency($message, array $context = []): void
{
$this->log(LogLevel::EMERGENCY, $message, $context);
}
public function alert($message, array $context = []): void
{
$this->log(LogLevel::ALERT, $message, $context);
}
public function critical($message, array $context = []): void
{
$this->log(LogLevel::CRITICAL, $message, $context);
}
public function error($message, array $context = []): void
{
$this->log(LogLevel::ERROR, $message, $context);
}
public function warning($message, array $context = []): void
{
$this->log(LogLevel::WARNING, $message, $context);
}
public function notice($message, array $context = []): void
{
$this->log(LogLevel::NOTICE, $message, $context);
}
public function info($message, array $context = []): void
{
$this->log(LogLevel::INFO, $message, $context);
}
public function debug($message, array $context = []): void
{
$this->log(LogLevel::DEBUG, $message, $context);
}
/* ---------------- Helpers ---------------- */
private function interpolate(string $message, array $context): string
{
$replace = [];
foreach ($context as $key => $value) {
if (is_scalar($value) || $value instanceof \Stringable) {
$replace['{' . $key . '}'] = (string)$value;
}
}
return strtr($message, $replace);
}
private function getLines(string $file): int
{
if (!file_exists($file)) {
return 0;
}
$lines = 0;
$fh = fopen($file, 'rb');
if (!$fh) {
return 0;
}
while (!feof($fh)) {
$lines += substr_count(fread($fh, 8192), "\n");
}
fclose($fh);
return $lines;
}
public function __destruct()
{
if ($this->handle && is_resource($this->handle)) {
fclose($this->handle);
}
}
}

@ -82,7 +82,7 @@ final class view {
* @param string $render_path * @param string $render_path
* @throws Exception * @throws Exception
*/ */
public function set_view(string $view_file = null, ViewType $type = ViewType::PHP): void { public function set_view(?string $view_file = null, ViewType $type = ViewType::PHP): void {
if ($view_file === null) { if ($view_file === null) {
return; return;
} }
@ -147,7 +147,7 @@ final class view {
* @param mixed $name Name of the variable to set in the view, or an array of key/value pairs where each key is the variable and each value is the value to set. * @param mixed $name Name of the variable to set in the view, or an array of key/value pairs where each key is the variable and each value is the value to set.
* @param mixed $value Value of the variable to set in the view. * @param mixed $value Value of the variable to set in the view.
*/ */
public function set($name, $value = null): void { public function set($name, mixed $value = null): void {
if (is_array($name)) { if (is_array($name)) {
foreach ($name as $var_name => $value) { foreach ($name as $var_name => $value) {
$this->vars[$var_name] = $value; $this->vars[$var_name] = $value;
@ -162,7 +162,7 @@ final class view {
* @param type $local * @param type $local
* @param string $file * @param string $file
*/ */
public function render($local, string $file = null, ViewType $type = ViewType::PHP) { public function render($local, ?string $file = null, ViewType $type = ViewType::PHP) {
echo $this->fetch($local, $file, $type); echo $this->fetch($local, $file, $type);
} }
@ -171,7 +171,7 @@ final class view {
* @param type $local = $this * @param type $local = $this
* @param $file (optional view file) * @param $file (optional view file)
*/ */
public function fetch($local, string $file = null, ViewType $type = ViewType::PHP): string { public function fetch($local, ?string $file = null, ViewType $type = ViewType::PHP): string {
$page_output = ob_get_clean(); // Get echos before View $page_output = ob_get_clean(); // Get echos before View
bootstrap\views::ob_start(); bootstrap\views::ob_start();
$saved_ob_level = ob_get_level(); $saved_ob_level = ob_get_level();

Loading…
Cancel
Save