Глава 45: redis

This commit is contained in:
Igor Simdyanov
2022-07-10 16:02:35 +03:00
parent 7c41cafa92
commit c0889e2420
23 changed files with 478 additions and 0 deletions

View File

@ -0,0 +1,35 @@
<?php
namespace MVC\Controllers;
class Controller
{
public string $path;
public Router $router;
public object $model;
public function __construct(string $path)
{
$this->path = $path;
$this->router = Router::parse($path);
$class = 'MVC\\Models\\' . ucfirst($this->router->model);
$this->model = new $class();
if($this->router->id) {
$this->model = $this->model->collection[$this->router->id];
}
}
public function render() : string
{
$class = get_class($this->model);
$class = substr($class, strrpos($class, '\\') + 1);
$decorator = \MVC\Decorators\DecoratorFactory::create(
$class,
$this->model);
$view = \MVC\Views\ViewFactory::create(
$this->router->ext,
$class,
$decorator);
return $view->render();
}
}

View File

@ -0,0 +1,67 @@
<?php
namespace MVC\Controllers;
class ControllerCache
{
public string $path;
private string $class;
private Router $router;
private object $model;
private object $redis;
public function __construct(string $path, object $redis)
{
$this->path = $path;
$this->redis = $redis;
}
public function render() : string
{
$cache = $this->redis->get($this->path);
if (!$cache) {
$decorator = \MVC\Decorators\DecoratorFactory::create(
$this->getClass(),
$this->getModel());
$view = \MVC\Views\ViewFactory::create(
$this->getRouter()->ext,
$this->getClass(),
$decorator);
$cache = $view->render();
$this->redis->set($this->path, $cache);
}
return $cache;
}
private function getClass() : string
{
if (empty($this->class)) {
$class = get_class($this->getModel());
$this->class = substr($class, strrpos($class, '\\') + 1);
}
return $this->class;
}
private function getRouter() : Router
{
if (empty($this->router)) {
$this->router = Router::parse($this->path);
}
return $this->router;
}
private function getModel() : object
{
if (empty($this->model)) {
$class = 'MVC\\Models\\' . ucfirst($this->getRouter()->model);
$this->model = new $class();
if ($this->getRouter()->id) {
$this->model = $this->model->collection[$this->getRouter()->id];
}
}
return $this->model;
}
}

View File

@ -0,0 +1,60 @@
<?php
namespace MVC\Controllers;
class ControllerLazy
{
public string $path;
private string $class;
private Router $router;
private object $model;
public function __construct(string $path)
{
$this->path = $path;
}
public function render() : string
{
$decorator = \MVC\Decorators\DecoratorFactory::create(
$this->getClass(),
$this->getModel());
$view = \MVC\Views\ViewFactory::create(
$this->getRouter()->ext,
$this->getClass(),
$decorator);
return $view->render();
}
private function getClass() : string
{
if (empty($this->class)) {
$class = get_class($this->getModel());
$this->class = substr($class, strrpos($class, '\\') + 1);
}
return $this->class;
}
private function getRouter() : Router
{
if (empty($this->router)) {
$this->router = Router::parse($this->path);
}
return $this->router;
}
private function getModel() : object
{
if (empty($this->model)) {
$class = 'MVC\\Models\\' . ucfirst($this->getRouter()->model);
$this->model = new $class();
if ($this->getRouter()->id) {
$this->model = $this->model->collection[$this->getRouter()->id];
}
}
return $this->model;
}
}

View File

@ -0,0 +1,26 @@
<?php
namespace MVC\Controllers;
class Router
{
public string $model;
public ?string $ext;
public ?int $id;
public static function parse(string $path) : Router
{
list($path, $ext) = explode('.', $path);
$arr = explode('/', $path);
return new self($arr[0], $ext, count($arr) > 1 ? $arr[1] : null);
}
private function __construct(
string $model,
?string $ext = null,
?int $id = null)
{
$this->model = $model;
$this->ext = $ext;
$this->id = $id;
}
}

View File

@ -0,0 +1,15 @@
<?php
namespace MVC\Decorators;
abstract class DecoratorFactory
{
public static function create(string $class, object $model)
{
$cls = 'MVC\\Decorators\\' . ucfirst($class) . 'Decorator';
return new $cls($model);
}
abstract public function title() : string;
abstract public function body() : string;
abstract public function items() : string;
}

View File

@ -0,0 +1,32 @@
<?php
namespace MVC\Decorators;
class UserDecorator extends DecoratorFactory
{
public $user;
public function __construct(\MVC\Models\User $user)
{
$this->user = $user;
}
public function title() : string
{
return implode(' ', [$this->user->first_name, $this->user->last_name]);
}
public function body() : string
{
return '<strong>' . htmlspecialchars($this->title()) . '</strong> '.
'(' . htmlspecialchars($this->user->email) . ')';
}
public function items() : string
{
return '<item>'.
'<title>' . htmlspecialchars($this->title()) . '</title>' .
'<email>' . htmlspecialchars($this->user->email) . '</email>'.
'</item>';
}
}

View File

@ -0,0 +1,45 @@
<?php
namespace MVC\Decorators;
class UsersDecorator extends DecoratorFactory
{
public $users;
public function __construct(\MVC\Models\Users $users)
{
$this->users = $users;
}
public function title() : string
{
return 'Пользователи';
}
public function collection_render(
callable $call,
string $separator = '<br />') : string
{
return implode(
$separator,
array_map($call, $this->users->collection)
);
}
public function body() : string
{
return $this->collection_render(
function($item){
$decorated_item = new UserDecorator($item);
return $decorated_item->body();
});
}
public function items() : string
{
return $this->collection_render(
function($item){
$decorated_item = new UserDecorator($item);
return $decorated_item->items();
}, '');
}
}

11
redis/mvc/models/user.php Normal file
View File

@ -0,0 +1,11 @@
<?php
namespace MVC\Models;
class User
{
public function __construct(
public string $email,
private string $password,
public ?string $first_name = null,
public ?string $last_name = null) {}
}

View File

@ -0,0 +1,24 @@
<?php
namespace MVC\Models;
class Users
{
public $collection;
public function __construct(public ?array $users = null)
{
$users ??= [
new User(
'dmitry.koterov@gmail.com',
'password',
'Дмитрий',
'Котеров'),
new User(
'igorsimdyanov@gmail.com',
'password',
'Игорь',
'Симдянов')
];
$this->collection = $users;
}
}

View File

@ -0,0 +1,34 @@
<?php
namespace MVC\Views;
class HtmlView extends ViewFactory
{
const LAYOUT = <<<HTML
<!DOCTYPE html>
<html lang="ru">
<head>
<title>{{{title}}}</title>
<meta charset='utf-8' />
</head>
<body>{{{body}}}</body>
</html>
HTML;
protected $replacements;
public function __construct(object $decorator)
{
$this->replacements = [
'{{{title}}}' => $decorator->title(),
'{{{body}}}' => $decorator->body()
];
}
public function render() : string
{
return str_replace(
array_keys($this->replacements),
array_values($this->replacements),
self::LAYOUT);
}
}

View File

@ -0,0 +1,34 @@
<?php
namespace MVC\Views;
class RssView extends ViewFactory
{
const LAYOUT = <<<HTML
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" />
<channel>
<title>{{{title}}}</title>
<link>http://example.com/</link>
{{{items}}}
</channel>
</rss>
HTML;
protected $replacements;
public function __construct(object $decorator)
{
$this->replacements = [
'{{{title}}}' => $decorator->title(),
'{{{items}}}' => $decorator->items()
];
}
public function render() : string
{
return str_replace(
array_keys($this->replacements),
array_values($this->replacements),
self::LAYOUT);
}
}

View File

@ -0,0 +1,4 @@
<?php
namespace MVC\Views;
class UserHtmlView extends HtmlView {}

View File

@ -0,0 +1,4 @@
<?php
namespace MVC\Views;
class UserRssView extends RssView {}

View File

@ -0,0 +1,4 @@
<?php
namespace MVC\Views;
class UsersHtmlView extends HtmlView {}

View File

@ -0,0 +1,4 @@
<?php
namespace MVC\Views;
class UsersRssView extends RssView {}

View File

@ -0,0 +1,18 @@
<?php
namespace MVC\Views;
abstract class ViewFactory
{
abstract public function render() : string;
public static function create(
string $type,
string $class,
\MVC\Decorators\DecoratorFactory $decorator) : ViewFactory
{
$class = 'MVC\\Views\\' . ucfirst($class) . ucfirst($type) . 'View';
$obj = new $class($decorator);
return $obj;
}
}