Всем привет.
Я (мы как фирма) допиливаем платформу от поставщика, платформа это плагин для WordPress. С фронтендом, JS, HTML я знаком лишь постольку поскольку, поэтому приведённые решения могут оказаться не грамотными, но суть статьи не в этом.
Суть в том что бы наглядно показать, почему иногда вместо двух строчек кода, будет правильным решением написать двести.
Начинающих разработчиков, и разработчиков с опытом, для которых такая мысль выглядит сомнительной, прошу под кат.
Введение
Читать статью не читая коменты в коде, не имеет смысла, потому что коменты кода не продублированы в тексте статьи и текст статьи подразумевает что читатель с коментами ознакомился.
Задача
Необходимо было внести изменения в JS, изменения я вношу в отдельные файлы, что бы как можно меньше "загрязнять" исходный код поставщика платформы, так в будущем будет проще адаптировать обновления исходников платформы.
Соответственно код нового функционала находиться в новых файлах которые надо подгружать на страничке.
Задача: требуется при загрузке страницы подгружать определённые файлы.
Первый блин комом
+<script src="e-cryptex.js"></script>
+<script src="wp-content/themes/tol-child/js/child_realforex.js"></script>
(строчки с "+" это новые строки в исходном коде)
Решение было протестировано для главной страницы и там оно работало, позже выяснилось что для страниц с адресом example.com/about, решение не работало, потому что браузер пытался подгрузить example.com/about/e-cryptex.js и браузер получал — ошибку 404, потому что файл реально лежал в корне — example.com/e-cryptex.js .
Второй вариант
Посмотрел как файлы к страничке цепляют разработчики платформы:
wp_register_script(FILE-ID,FILE-PATH);
wp_enqueue_script(FILE-ID);
Файлы прикрепляются с использованием функционала WordPress — ок, сделаем так же:
// Было:
-<script src="e-cryptex.js"></script>
-<script src="wp-content/themes/tol-child/js/child_realforex.js"></script>
// Стало :
+<?php
+const E_CRYPTEX_JS ='e-cryptex_js';
+wp_register_script(E_CRYPTEX_JS,'/e-cryptex.js',array(),null);
+wp_enqueue_script(E_CRYPTEX_JS);
+const CHILD_REALFOREX_JS = 'child_realforex_js';
+wp_register_script(
+ CHILD_REALFOREX_JS,
+ '/wp-content/themes/tol-child/js/child_realforex.js',
+ array(E_CRYPTEX_JS),
+ null);
+wp_enqueue_script(CHILD_REALFOREX_JS);
+?>
(строчки с "+" это новые строки в исходном коде, строчки с "-" это строки удалённые из исходного кода).
Проверил — работает, ок.
Было две строчки — стало 12, всё в пределах одного файла.
Рефакторинг
Посмотрел я на этот код, и моё чувство прекрасного взбунтовалось:
- человек не знакомый с WordPress ни чего не поймёт — придётся лезть в справочник что бы понять назначение функций wp_register_script() и wp_enqueue_script()
- явно делается одно и то же два раза подряд, аргументы только разные — нарушается DRY
Ок, рефакторим.
Во первых, делаем класс (один файл), во вторых, класс подключаем и используем (изменяем другой файл).
Делаем класс
+class Migesco {
+
+ const SCRIPT = 'script';
+ const SOURCE = 'source';
+ const DEPENDENCY = 'dependency';
+
// На всех страницах, где был изменён функционал используется 'configuration.js',
// поэтому для него делаем "жёсткий" вариант подгрузки файла.
+ static function attachConfigurationJS(){
+ $configurationFiles = array(
+ array(Migesco::SCRIPT => 'configuration.js',
+ Migesco::SOURCE=>'/configuration.js'));
+ Migesco::includeScriptFiles($configurationFiles);
+ }
// На вход получаем массив с параметрами файлов и все их по очереди подключаем
+ static function includeScriptFiles($scriptFiles){
+ foreach ($scriptFiles as $scriptFile){
+ $dependency = array_key_exists(self::DEPENDENCY,$scriptFiles)
+ ? $scriptFile[self::DEPENDENCY]
+ : array();
+ self::includeScript($scriptFile[self::SCRIPT],$scriptFile[self::SOURCE],$dependency);
+ }
+ }
// Собственно подключение одного скрипта,
// реализация скрыта от "пользователя", все как Ленин завещал
// (метод надо было ещё приватным сделать)
+ static function includeScript($id,$source,$dependency){
+ wp_register_script($id,$source,$dependency,null);
+ wp_enqueue_script($id);
+ }
+}
Подключаем и используем
<?php
//Было:
-const E_CRYPTEX_JS ='e-cryptex_js';
-wp_register_script(E_CRYPTEX_JS,'/e-cryptex.js',array(),null);
-wp_enqueue_script(E_CRYPTEX_JS);
-const CHILD_REALFOREX_JS = 'child_realforex_js';
-wp_register_script(
- CHILD_REALFOREX_JS,
- '/wp-content/themes/tol-child/js/child_realforex.js',
- array(E_CRYPTEX_JS),
- null);
-wp_enqueue_script(CHILD_REALFOREX_JS);
// Стало:
// Подключаем
+require_once(ABSPATH . 'configuration.php');
// Используем
+const ECRYPTEX_JS = 'cryptex';
+const TRADEROOM_SCRIPT_FILES = array(
+ array(Migesco::SCRIPT => ECRYPTEX_JS,
+ Migesco::SOURCE=>'/e-cryptex.js'),
+ array(Migesco::SCRIPT => 'child_realforex',
+ Migesco::SOURCE=>'/wp-content/themes/tol-child/js/child_realforex.js',
+ Migesco::DEPENDENCY =>ECRYPTEX_JS)
+);
+Migesco::includeScriptFiles(TRADEROOM_SCRIPT_FILES);
?>
Было 12 строчек исходников в одном файле стало 35, и в двух (поддерживай это потом, ищи рыщи где бы что бы ещё подправить, что бы ни чего не забыть, не пропустить, не упустить).
И ещё раз рефактринг
Посмотрел на новый код:
- какие то статические методы,
- какие то константы…
топорно смотрится! Помниться такой совет: "если у конструктора нет аргументов, то нужен ли такой класс ?"
Давайте переделаем, но нормальный класс, с нормальным конструктором и методами.
Класс
// Было:
-class Migesco {
-
- const SCRIPT = 'script';
- const SOURCE = 'source';
- const DEPENDENCY = 'dependency';
-
- static function attachConfigurationJS(){
- $configurationFiles = array(
- array(Migesco::SCRIPT => 'configuration.js',
- Migesco::SOURCE=>'/configuration.js'));
- Migesco::includeScriptFiles($configurationFiles);
- }
- static function includeScriptFiles($scriptFiles){
- foreach ($scriptFiles as $scriptFile){
- $dependency = array_key_exists(self::DEPENDENCY,$scriptFiles)
- ? $scriptFile[self::DEPENDENCY]
- : array();
- self::includeScript($scriptFile[self::SCRIPT],$scriptFile[self::SOURCE],$dependency);
- }
- }
- static function includeScript($id,$source,$dependency){
- wp_register_script($id,$source,$dependency,null);
- wp_enqueue_script($id);
- }
-}
//Стало:
// Один класс пришлось разделить на три:
// Один управляет
// Другой выполняет
// Третий данные хранит
//Для объединения классов делаем отдельное пространство имён
+namespace Migesco;
+
+
// Класс Управляет прикреплением файлов к html-страничке
+class Configurator
+{
// Тот самый жёсткий метод для привязки файла общего для всех страниц с изменённым функционалом
+ static function attachConfigurationJS()
+ {
+ $configurationFiles = array(
+ (new WebResource('configuration.js'))->setSource('/configuration.js'));
+ self::attachFiles($configurationFiles);
+ }
+
// Метод для прикрепления файла к html-страничке
+ static function attachFiles($resourceList)
+ {
+ (new Registrar($resourceList))->toRegistrate();
+ }
+}
+
// Класс Выполняет прикрепление файла к html-страничке
+class Registrar
+{
// Массив файлов для прикрепления
+ public $list = array();
// это свойство должно быть private (задел на будущий рефакторинг)
+ /** @var WebResource $resource */
+ public $resource = null;
+
+ public function __construct($list)
+ {
+ $isArray = is_array($list);
+ if ($isArray) {
+ $this->list = $list;
+ }
+ }
+
// Метод для регистрации файла в WordPress
+ function registerScript()
+ {
+ wp_register_script(
+ $this->resource->getName(),
+ $this->resource->getSource(),
+ $this->resource->getDependency(),
+ null);
+ }
+
// Метод для прикрепления файла
+ function enqueueScript()
+ {
+ wp_enqueue_script($this->resource->getName());
+ }
+
// Метод для прикрепления списка файлов
+ function toRegistrate()
+ {
+ $result = false;
+ foreach ($this->list as $resource) {
+ /** @var WebResource $resource */
+ $isResource = $resource instanceof WebResource;
+ if ($isResource) {
+ $this->resource = $resource;
+ $this->registerScript();
+ $this->enqueueScript();
+
+ $result = true;
+ }
+ }
+ return $result;
+ }
+}
+
// Класс для Хранения данных
+class WebResource
+{
// Путь к файлу
+ public $source = '';
// Идентификатор файла
+ public $name = '';
// Зависимости файла
+ public $dependency = array();
+
+ public function __construct($name)
+ {
+ $this->setName($name);
+ }
+
+ /**
+ * @param string $source
+ * @return WebResource
+ */
+ public function setSource($source)
+ {
+ $this->source = strval($source);
+ return $this;
+ }
+
+ /**
+ * @param string $name
+ * @return WebResource
+ */
+ public function setName($name)
+ {
+ $this->name = strval($name);
+ return $this;
+ }
+
+ /**
+ * @param array $dependency
+ * @return WebResource
+ */
+ public function setDependency($dependency)
+ {
+ $isArray = is_array($dependency);
+ if ($isArray) {
+ $this->dependency = $dependency;
+ }
+ return $this;
+ }
+
+ /**
+ * @return string
+ */
+ public function getSource()
+ {
+ return $this->source;
+ }
+
+ /**
+ * @return string
+ */
+ public function getName()
+ {
+ return $this->name;
+ }
+
+ /**
+ * @return array
+ */
+ public function getDependency()
+ {
+ return $this->dependency;
+ }
+}
Использование
<?php
// Было:
-const TRADEROOM_SCRIPT_FILES = array(
- array(Migesco::SCRIPT => ECRYPTEX_JS,
- Migesco::SOURCE=>'/e-cryptex.js'),
- array(Migesco::SCRIPT => 'child_realforex',
- Migesco::SOURCE=>'/wp-content/themes/tol-child/js/child_realforex.js',
- Migesco::DEPENDENCY =>ECRYPTEX_JS)
-);
-Migesco::includeScriptFiles(TRADEROOM_SCRIPT_FILES);
// Стало:
+$traderoomScriptFiles = array(
+ (new Migesco\WebResource(ECRYPTEX_JS))
+ ->setSource('/e-cryptex.js'),
+ (new Migesco\WebResource('child_realforex'))
+ ->setSource('/wp-content/themes/tol-child/js/child_realforex.js')
+ ->setDependency(array(ECRYPTEX_JS))
+);
+Migesco\Configurator::attachFiles($traderoomScriptFiles);
?>
Можно ещё раз сделать рефакторинг(платформа работает на PHP 5.6 — с удовольствием бы везде расставил типы, но к сожалению нельзя, можно статичный класс Configurator, сделать более "человеческим", например, инициализировать от списка файлов — веб-ресурсов и метод attachFiles сделать не статическим), но идеальные вещи для идеального мира, мы живём в реальном, и это вносит свои коррективы — время на задачу потрачено — работа по задаче прекращена.
Итого: было 35 строк в исходниках в двух файлах, стало ~170, также в двух файлах.
Что мы получили ?
- Теперь не надо лезть в хэлп WordPress`а, что бы понять назначение параметров "функций".
- Теперь у нас есть обёртка для подключения файлов и мы можем без болезненно изменять алгоритм подключения файлов — не придётся править все вызовы wp_register_script и wp_enqueue_script
- Теперь мы можем сменить WordPress на что угодно и переписать придётся только класс
Registrar, не надо заменять все вызовы wp_register_script и wp_enqueue_script и следовать логике WordPress`а.
Стоило оно того?
У каждого свой подход к поддержке кодовой базы и своё мнение.
Мой ответ — да.