Данная статья посвящена внедрению ORM Doctrine в ядро CMS WordPress. Все вопросы и утверждения по типу: «А зачем», «А почему», «Да это только наложит дополнительный оверхэд и ничего с этого не выиграешь», возможно, будут проигнорированы:)
Я считаю, что Doctrine имеет место быть в ядре WordPress, как минимум, для удобства разработки крупного сайта в большой команде из 10+ человек, для совместимости WordPress с PostgreSQL и обратной совместимости с MySQL (как пример) и использования обновления схемы БД, миграции и прочего полезного «сахара». Должна же быть возможность использовать при необходимости другую СУБД вместо MySQL. Спросите зачем PostgreSQL в вордпрессе? Вы просто еще мало видели:)
В настоящее время, чтобы сертифицироваться в Российском стеке, необходимо использование именно PostgreSQL PRO лицензии. К примеру, в Битриксе есть возможность развернуться на постгре из коробки. Почему разработчики ядра wordpress не предусмотрели такую возможность — мне не совсем понятно. Ну да ладно.
Итак, начнем.
Будем использовать composer в качестве пакетного менеджера.
Для начала установим Doctrine:
composer require doctrine/orm
Также для работы доктрины нам понадобится symfony/cache
composer require symfony/cache
И еще миграции:)
composer require doctrine/migrations
Далее добавим файл db.php в ваш проект (дира wp-content по дефолту, если не используется другая структура проекта по типу как в https://roots.io/bedrock/), чтобы включить необходимые файлы и классы в проект.
Код файла db.php:
<?php if (!defined('DOCTRINE4WP_ROOT')) { define('DOCTRINE4WP_DEBUG', false); define('DOCTRINE4WP_LOG_ERRORS', true); define('DOCTRINE4WP_INSECURE', false); if (file_exists(dirname(__FILE__) . '/doctrine4wp')) define('DOCTRINE4WP_ROOT', dirname(__FILE__) . '/doctrine4wp'); else if (file_exists($_SERVER['DOCUMENT_ROOT'] . '/app/plugins/doctrine4wp')) define('DOCTRINE4WP_ROOT', $_SERVER['DOCUMENT_ROOT'] . '/app/plugins/doctrine4wp'); else if (file_exists($_SERVER['DOCUMENT_ROOT'] . '/app/doctrine4wp')) define('DOCTRINE4WP_ROOT', $_SERVER['DOCUMENT_ROOT'] . '/app/pg4wp'); else die('DOCTRINE4WP file directory not found'); require_once(DOCTRINE4WP_ROOT . '/core.php'); } // Protection against multiple loading
Затем, добавим директорию doctrine4wp к проекту. В директории будет всего 2 файла: core.php и class-wpdb.php (перезаписанный стандартный вп-шный класс для работы с БД). Также в директории будет динамически создана поддиректория logs для хранения логов ошибок запросов к бд и т д.
Код файла core.php:
<?php /** * @package PostgreSQL_For_Wordpress * @version $Id$ * @author GOSWEB */ /** * This file does all the initialisation tasks */ // Logs are put in the pg4wp directory define('DOCTRINE4WP_LOG', DOCTRINE4WP_ROOT . '/logs/'); // Check if the logs directory is needed and exists or create it if possible if ((DOCTRINE4WP_DEBUG || DOCTRINE4WP_LOG_ERRORS) && !file_exists(DOCTRINE4WP_LOG) && is_writable(dirname(DOCTRINE4WP_LOG))) mkdir(DOCTRINE4WP_LOG); // Load the driver defined in 'db.php' + composer dependencies and new wpdb2 class $params = [ 'db' => DB_NAME, 'password' => DB_PASSWORD, 'user' => DB_USER, 'host' => DB_HOST, 'port' => $GLOBALS['_ENV']['DB_PORT'] ?? '3306' ]; require_once(DOCTRINE4WP_ROOT . '/class-wpdb.php'); try { Src\WpDoctrine\WpOrm::get_instance()->init($params); if (!isset($wpdb)) { $wpdb = wpdb2::get_instance(Src\WpDoctrine\WpOrm::get_instance()->getConnection(), $params); } } catch (\Doctrine\DBAL\Exception $e) { error_log($e->getMessage()); }
Перезаписываем стандартный вп-шный класс wpdb и меняем его на wpdb2.
Файлик class-wpdb.php (здесь не показываю ввиду его объема)
Далее подключаем основной класс для инициализации Doctrine. Для этого в корне проекта создаем директорию src со следующей структурой:
Файл DbSingleton.php (используется в классе wpdb2 шагом ранее):
<?php namespace Src\Patterns; use Doctrine\DBAL\Connection; abstract class DbSingleton { private static array $instances = array(); public static function get_instance(Connection $conn, array $params) { $class = get_called_class(); if (array_key_exists($class, self::$instances) === false) { self::$instances[$class] = new $class($conn, $params); } return self::$instances[$class]; } }
Код файла WpOrm.php
<?php namespace Src\WpDoctrine; use Doctrine\DBAL\Connection; use Doctrine\DBAL\DriverManager; use Doctrine\DBAL\Exception; use Doctrine\ORM\EntityManager; use Doctrine\ORM\Exception\MissingMappingDriverImplementation; use Doctrine\ORM\ORMSetup; class WpOrm { private static array $instances = array(); private Connection $connection; private ?EntityManager $entityManager = null; /** * @return WpOrm */ public static function get_instance(): WpOrm { $class = get_called_class(); if (array_key_exists($class, self::$instances) === false) { self::$instances[$class] = new $class(); } return self::$instances[$class]; } /** * @param array $params * @return void * @throws Exception */ public function init(array $params): void { $paths = [dirname(__FILE__, 2) . '/Entity']; $dbParams = [ 'driver' => $_ENV['DB_DRIVER'] ?? 'pdo_mysql', 'host' => $params['host'], 'user' => $params['user'], 'password' => $params['password'], 'dbname' => $params['db'], 'port' => $params['port'], ]; $config = ORMSetup::createAttributeMetadataConfiguration($paths, true); $this->connection = DriverManager::getConnection($dbParams, $config); try { $this->entityManager = new EntityManager($this->connection, $config); } catch (MissingMappingDriverImplementation $e) { error_log($e->getMessage()); } } public function getManager(): ?EntityManager { return $this->entityManager; } public function getConnection(): Connection { return $this->connection; } }
Модельки подключаются из директории src/Entity. Принцип работы такой же как и в Symfony https://symfony.com/doc/current/doctrine.html.
В последнюю очередь нам необходимы файлы для работы с cli, чтобы завелись команды на обновление схемы БД и мигрции.
Создадим директорию config и в ней добавим 2 файла:
Теперь нам также будут доступны команды для создания и обновления схемы БД, и миграции (миграции создаются в директории src/Migrations):
php bin/console doctrine:schema:create
php bin/console doctrine:schema:update --force
php bin/console doctrine:migrations:migrate
Собственно все 🙂
ссылка на оригинал статьи https://habr.com/ru/articles/854058/
Добавить комментарий