diff --git a/docs/Gang_of_Four_Design_Patterns.pdf b/docs/Gang_of_Four_Design_Patterns.pdf new file mode 100644 index 0000000..117e215 Binary files /dev/null and b/docs/Gang_of_Four_Design_Patterns.pdf differ diff --git a/docs/Notes.txt b/docs/Notes.txt new file mode 100644 index 0000000..41c83d4 --- /dev/null +++ b/docs/Notes.txt @@ -0,0 +1,3 @@ +About Data Transfer Objects, etc...: + +https://chatgpt.com/share/6956d98b-3d5c-8001-8139-a8598747b111 \ No newline at end of file diff --git a/docs/OOP_Design_Patterns.html b/docs/OOP_Design_Patterns.html new file mode 100644 index 0000000..6f61010 --- /dev/null +++ b/docs/OOP_Design_Patterns.html @@ -0,0 +1,62 @@ + + + + + + Gang of Four Design Patterns + + +

23 Classic Gang of Four Design Patterns

+ +

Generated by ChatGPT:

+ +

Creational Patterns (deal with object creation)

+
    +
  1. Singleton - Ensures a class has only one instance and provides a global point of access to it.
  2. +
  3. Factory Method - Defines an interface for creating objects but lets subclasses decide which class to instantiate.
  4. +
  5. Abstract Factory - Provides an interface for creating families of related objects without specifying their concrete classes.
  6. +
  7. Builder - Separates the construction of a complex object from its representation, allowing the same construction process to create different representations.
  8. +
  9. Prototype - Creates new objects by copying an existing object (prototype) rather than creating from scratch.
  10. +
+ +

Structural Patterns (deal with object composition)

+
    +
  1. Adapter - Converts the interface of one class into another interface that clients expect, enabling incompatible classes to work together.
  2. +
  3. Bridge - Decouples an abstraction from its implementation so they can vary independently, preventing a permanent binding between them.
  4. +
  5. Composite - Composes objects into tree structures to represent part-whole hierarchies, letting clients treat individual objects and compositions uniformly.
  6. +
  7. Decorator - Attaches additional responsibilities to an object dynamically, providing a flexible alternative to subclassing for extending functionality.
  8. +
  9. Facade - Provides a unified, simplified interface to a complex subsystem, making it easier to use.
  10. +
  11. Flyweight - Minimizes memory usage by sharing as much data as possible with similar objects; used when large numbers of objects are needed.
  12. +
  13. Proxy - Provides a surrogate or placeholder for another object to control access to it, useful for lazy initialization, access control, or logging.
  14. +
+ +

Behavioral Patterns (deal with object interaction and responsibility)

+
    +
  1. Chain of Responsibility - Passes a request along a chain of handlers, where each handler decides either to process the request or pass it to the next handler.
  2. +
  3. Command - Encapsulates a request as an object, thereby allowing parameterization of clients with different requests and supporting undoable operations.
  4. +
  5. Interpreter - Defines a grammatical representation for a language and an interpreter to evaluate sentences in that language.
  6. +
  7. Iterator - Provides a way to access elements of an aggregate object sequentially without exposing its underlying representation.
  8. +
  9. Mediator - Defines an object that encapsulates how a set of objects interact, promoting loose coupling by preventing objects from referring to each other explicitly.
  10. +
  11. Memento - Captures and externalizes an object's internal state without violating encapsulation, so the object can be restored to this state later.
  12. +
  13. Observer - Defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.
  14. +
  15. State - Allows an object to alter its behavior when its internal state changes, appearing to change its class.
  16. +
  17. Strategy - Defines a family of algorithms, encapsulates each one, and makes them interchangeable, letting the algorithm vary independently from clients.
  18. +
  19. Template Method - 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.
  20. +
  21. Visitor - Represents an operation to be performed on elements of an object structure, letting you define new operations without changing the classes of the elements.
  22. +
+ +

These patterns provide proven solutions to common software design problems, promoting code reuse, flexibility, and maintainability in object-oriented systems.

+ +

Links to more external resources not mine...

+ +
+

I'm not affiliated with nor profit from these Books, they are just here for your and my convenience.

+

Modern PHP 8 Design Patterns Online Version: https://designpatternsphp.readthedocs.io/en/latest/

+

PDF Version: https://designpatternsphp.readthedocs.io/_/downloads/en/latest/pdf/

+

Nice Book for sale: Buy Dive Into DESIGN PATTERNS An Ebook on design patterns and the principles behind them: https://refactoring.guru/design-patterns/book

+

PHP Code from the Book above: https://refactoring.guru/design-patterns/php, If you liked it; Please support them by buying the book above...

+

"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: https://www.informit.com/store/design-patterns-elements-of-reusable-object-oriented-9780201633610

+

More on The Addison-Wesley Professional Computing Series

+
+ + \ No newline at end of file diff --git a/docs/TODO.md b/docs/TODO.md index 43bde7d..4d1c170 100644 --- a/docs/TODO.md +++ b/docs/TODO.md @@ -34,7 +34,13 @@ - [ ] → Sane Config/Service file defaults - [ ] → Sane Folder Structure and Documentation - [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: - [x] → LazyCollections, LazyObjects, Money Class - [ ] → Tests diff --git a/src/bootstrap/errors.php b/src/bootstrap/errors.php index f5f653d..4b4737f 100644 --- a/src/bootstrap/errors.php +++ b/src/bootstrap/errors.php @@ -145,7 +145,7 @@ function formatMessage($message, $type = 'error') { } // 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 if (!(error_reporting() & $errno)) { return false; diff --git a/src/bootstrap/main.php b/src/bootstrap/main.php index e115bc4..686e197 100644 --- a/src/bootstrap/main.php +++ b/src/bootstrap/main.php @@ -64,9 +64,10 @@ final class configure { 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 return self::has(func_get_args()); @@ -195,9 +196,15 @@ final class di { ...$more ) { 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); + } + + $service_name = $entry; } - return $this->resolve($service_name); // Try to Auto-Wire + return $this->resolve(c); // Try to Auto-Wire } public function get_auto(string $service_name) { @@ -222,7 +229,7 @@ final class di { public function list_services_as_string(): string { 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) { try { $reflection_class = new \ReflectionClass($service_name); @@ -247,7 +254,7 @@ final class di { return new $service_name; } $dependencies = array_map( - function(\ReflectionParameter $param) { + function(\ReflectionParameter $param) use ($service_name) { $name = $param->getName(); $type = $param->getType(); if (! $type) { @@ -282,6 +289,8 @@ registry::get('loader')->add_namespace("Project", 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... if (! defined('ENVIRONMENT')) { if (is_live() === false) { diff --git a/src/classes/common.php b/src/classes/common.php index 1545fea..d9c2f10 100644 --- a/src/classes/common.php +++ b/src/classes/common.php @@ -150,7 +150,7 @@ final class common { 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) { return F::substr($string, $offset, strlen($string)); } else { diff --git a/src/classes/services/Logger.php b/src/classes/services/Logger.php new file mode 100644 index 0000000..8dbf961 --- /dev/null +++ b/src/classes/services/Logger.php @@ -0,0 +1,154 @@ + 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); + } + } +} diff --git a/src/classes/view.php b/src/classes/view.php index 89ff29b..d43bc2a 100644 --- a/src/classes/view.php +++ b/src/classes/view.php @@ -82,7 +82,7 @@ final class view { * @param string $render_path * @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) { 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 $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)) { foreach ($name as $var_name => $value) { $this->vars[$var_name] = $value; @@ -162,7 +162,7 @@ final class view { * @param type $local * @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); } @@ -171,7 +171,7 @@ final class view { * @param type $local = $this * @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 bootstrap\views::ob_start(); $saved_ob_level = ob_get_level();