Как стать автором
Обновить

PHP: Параметры в контексте

Время на прочтение5 мин
Количество просмотров688
Проблема:

Требуется, чтобы несколько взаимодействующих между собой объектов могли управлять логикой определенных методов.

Например: каждый из объектов имеет метод Data(), который возвращает данные, необходимые для отображения объекта на странице (данные для шаблонизатора). Например объект $news класса News должен возвратить 5 последних новостей в приемлемом для шаблонизатора виде, например в виде массива. В свою очередь News::Data() обращается поочередно к объектам $newsPost->Data() (к вложенным объектам) для получения данных, касающихся отдельной новости (заголовок, дата и т.д.). Однако в некоторых случаях требуется, чтобы NewsPosе::Data() возвращал не полные данные, а лишь заголовок (например на главной странице сайта), а в другом случае требуется, чтобы вернулись все данные, включая ссылки на «новости по теме».

Применение нескольких методов Data() ( DataShort(), DataFull() ) решило бы проблему, но хотелось бы более элегантного решения.

Управляющий скрипт (допустим, конструктор страницы) «знает» в каком виде NewsPost::Data() должен вернуть данные, однако он не может напрямую взаимодействовать с объектами класса NewsPost, потому как это «забота» класса News. Следовательно, все, что может скрипт, это «попросить» $news «попросить» $newsPost вернуть «сокращенные» данные.

Copy Source | Copy HTML
  1. $data = $news->Data('ask newsPost: return short data');


тогда внутри News::Data() будет что-то:

Copy Source | Copy HTML
  1. public function Data($askWhat)
  2. {
  3.         ...
  4.         $dataNews = $this->newsPost->Data('return short data');
  5.         ...
  6. }


возможно, NewsPost::Data() обращается еще к каким-то объектам, допустим NewsPostBody::Data() для получения собственно статьи. Тогда, получив запрос «short data» на NewsPost::Data(), нужно сделать запрос с параметром «body short» к методу NewsPostBody::Data(). Не обязательно «управляющему скрипту» знать об этом, однако нельзя блокировать возможность напрямую «дать указание» объекту класса NewsPostBody вернуть «короткий вариант» статьи. То есть что-то вроде:

Copy Source | Copy HTML
  1. $data = $news->Data('ask NewsPostBody: return short article');


Однако, возможна ситуация, когда нужно обращаться к методу NewsPostBody::Data() с разными параметрами, причем за один запрос. Например когда News содержит «новости сайта», где NewsPostBody::Data() должен всегда возвращать «необрезанную» версию. То есть что-то вроде:

Copy Source | Copy HTML
  1. $data = $news->Data('ask NewsPostBody(main news only): return short article');


или:

Copy Source | Copy HTML
  1. $data = $news->Data('return main news short body');


но тогда News::Data() должен сделать примерно следующее:

image

или еще сложнее, когда для SiteNewsBody::Data() передаются другие параметры, например 'return SEO friendly body'.

Вырисовываются некоторые технические требования:

  • управляющая составляющая (команда)
  • адресат (кому предназначается управляющая команда)
  • указание лишь класса объекта недопустимо, дополнительно требуется указать «адресата» на уровне «бизнес логики», или «контекст», так как возможно несколько значений одного и того же параметра для одного и того же класса (возможно даже объекта) в различных контекстах.


Context::Class::Command

Class, принципе, тоже в нектором свмсле «контекст», так что можно использовать «вложение контекстов»:

ContextInContextInContex::Command

Также следует подумать о расширенном использовании управляющей составляющей Command и предусмотреть возможность отделения аргумента от собственно «команды», напрмер «body_short=250», что может означать «ограничить статью до 250 символов». Имеем:

ContextInContext::Command[=Argument(s)];

Copy Source | Copy HTML
  1. $data = $news->Data(new Parameters('NewsBodyInMainNews:short=250;NewsBodyInSiteNews:seo_frendly;short=500;NewsBody:keepHtml'));


Попробуем набросать интерфейс «в живую»:

Copy Source | Copy HTML
  1. function News::Data($params)
  2. {
  3.             $newsData = new NewsData();
  4.  
  5.             // добавляем необходимые данные с параметрами в контексте 'SiteNews'
  6.             // должен использоваться параметр short=500 и seo_freindly и keepHtml
  7.  
  8.             $params->useContext('SiteNews');
  9.             $newsData->add( $this->getSiteNewsData($params) );
  10.             $params->dontUseContext('SiteNews');
  11.  
  12.             // добавляем необходимые данные с параметрами в контексте 'MainNews'
  13.             // должны использоваться только параметры short=250 и keepHtml
  14.  
  15.             $params->useContext('MainNews');
  16.  
  17.             $newsData->add( $this->getMainNewsData($params) );
  18.  
  19.             $params->dontUseContext('MainNews');
  20.  
  21.             return $newsData;
  22.  
  23. }
  24.  
  25. ...
  26.  
  27. function NewsBody::Data($params)
  28. {
  29.             $newsBodyData = new NewsBodyData();
  30.  
  31.             $params->useContext('NewsBody');
  32.  
  33.             $bodyLimit = $params->get('short');
  34.  
  35.             $newsBodyData->add('body', $this->getBody($bodyLimit));
  36.  
  37.             $params->dontUseContext('NewsBody');
  38.  
  39.             ...
  40.  
  41.             return $newsBodyData;
  42. }
  43.  
  44.  


Почти все готово для начала разработки класса. Подведем итог и выделим основные моменты в будущем классе:

  • Значение параметра можно задать в определенном «контексте», причем контекст может быть «вложенным» (NewsBodyInMainNewsInPage не то же самое что NewsBodyInSiteNewsInPage);
  • метод get() должен возвращать значение параметра в текущем контексте, заданным в useContext();
  • возможность «объединения» параметров (двух объектов класса Parameters с возможностью управления перегрузкой значений для одинаковых параметров)
  • возможность задавать параметры строкой, вида 'ContextInContext:param=value;param2' или вызывая метод set($parameter, $value, $context)


image

Можно приступать к реализации.

PS. топик был когда-то опубликован мною. Использую это паттэрн с тех пор, не задумываясь, новый ли это «велосипед» или нет. Возможно кому-то будет полезен. Буду рад обсудить кончно.
Теги:
Хабы:
Всего голосов 8: ↑3 и ↓5-2
Комментарии11

Публикации

Истории

Ближайшие события