[ Поиск ] - [ Пользователи ] - [ Календарь ]
Полная Версия: Композиция объектов
Лена
Есть класс View, объект которого создается в индексном файле:
$view = new View($registry);
$registry->set('view', $view);


Создали объект - записали в реестр.

Вызов View происходит в контроллере страницы:


class ProductCategoryCommand extends Command
{
public function doExecute()
{
$view = $this->registry->get('view');


//другой код....
$theme = $view->getTheme();
$typetpl = $view->getTypeTemplate();

$view->render(PAGE_PATH . "view/theme/" . $theme . "/template/" . $typetpl . "/product/category",

$param);
}
}


К системе надо добавить шаблонизаторы.
Создала класс TemplateView, в котором есть метод
AddTypeTemplate($template){}

switch($template){

case SMARTY:

//подключаем файлы шаблонизатора
break;

case TWIG:
//...
break;
}

}


Как лучше связать эти два класса? Может, какой-то шаблон использовать?
Просто во View создать объект TemplateView и его использовать?



Спустя 34 минуты, 17 секунд (5.09.2012 - 16:42) Oyeme написал(а):
Я советую Вам применить здесь паттерн:
http://www.phppatterns.com/docs/design/ada..._proxy_patterns

Спустя 6 часов, 41 минута, 40 секунд (5.09.2012 - 23:24) Лена написал(а):
Спасибо, пример хороший.
Что получилось. Привожу куски кода.
Класс View:

class View {

private $db;
public $request;
private $typetpl;
private $registry;
private $modules;
public $template_dir;

function __construct(Registry $registry)
{
$this->registry = $registry;
$this->db = $this->registry->get('DB');
$this->request = $this->registry->get('request');
$this->modules = $this->registry->get('modules');
$this->typetpl = $this->setTypeTemplate();
$this->template_dir = PAGE_PATH . "/view/theme/" . $this->getTheme() . "/template/native";
}

Класс адаптера:

class TemplateView extends View{

private $adaptee;
private $theme;

public function __construct($registry,$adaptee) {

parent::__construct($registry);

$this->theme = $this->getTheme();
$this->typetpl = $this->getTypeTemplate();

switch ($adaptee) {
case 'SMARTY':
$this->template_dir = PAGE_PATH . "view/theme/" . $this->theme . "/template/smarty";
require_once (PLUGINS_PATH . "smarty/Smarty.class.php");
$this->adaptee = new Smarty;
$this->adaptee->template_dir = $this->template_dir;

$this->adaptee->compile_dir = PAGE_PATH . "view/theme/" . $this->theme . "/template/smarty/templates_c/";
$this->adaptee->config_dir = PAGE_PATH . "view/theme/" . $this->theme . "/template/smarty/configs";
$this->adaptee->cache_dir = PAGE_PATH . "view/theme/" . $this->theme . "/template/smarty/cache";
break;
case 'TWIG':
$this->template_dir = PAGE_PATH . "view/theme/" . $this->theme . "/template/twig";
require_once (PLUGINS_PATH . '/Twig-v1.9.2-8/lib/Twig/Autoloader.php');
Twig_Autoloader::register();
$loader = new Twig_Loader_Filesystem($this->template_dir);

$this->adaptee = new Twig_Environment($loader, array(
'cache' => '/path/to/compilation_cache',

));


break;
default:
$this->template_dir = PAGE_PATH . "/view/theme/" . $this->theme . "/template/native";
break;
}



}
}


Класс контроллера, где создается объект или вью, или адаптера:

abstract class Command{

protected $registry;
protected $connect;
protected $view;
public $theme;
public $typetpl;
//адаптер под разные шаблонизаторы
private $adapter = true;

public function __construct(Registry $registry,$adaptee='') {
$this->registry = $registry;

$this->connect = $this->registry->get('connect');
$this->view = $this->registry->get('view');

if ($this->adapter)
$this->view = new TemplateView($registry,$adaptee='NATIVE');
else
$this->view= new View($registry);

$this->registry->set('view', $this->view);

$this->theme = $this->view->getTheme();
$this->typetpl = $this->view->getTypeTemplate();

}
abstract function doExecute();

Конкретная команда:
  class ProductCategoryCommand extends Command
{

public function doExecute()
{
$this->connect->model('product/category');
$this->model_product_category->updateMenu();

$ct = $this->categoryList();
$ct2 = $this->categoryForm();

$path = $this->view->template_dir . "/product/category";

$param = array(
'ct'=>$ct,
'ct2'=>$ct2
);
$this->view->render($path, $param);
}

}

Одно не сильно понятно. Зачем мне приватный ресурс private $adaptee; в адаптере, если я его нигде не использую? По примеру там вызываются свои методы для каждого, у меня методов нет или я не так поняла, по идее должно подхватиться это свойство, чтобы в контроллере вывелся нужный шаблон. Если кто может, помогите ,пожалуйста.

Спустя 11 часов, 46 минут, 41 секунда (6.09.2012 - 11:10) Лена написал(а):
В адаптер еще надо добавить метод render(), который подменит родительский метод. Схематично это так:

public function render($adaptee)
{
switch ($adaptee) {
case 'SMARTY':
$this->adaptee->assign('list',$list);
//$smarty->fetch();
$this->adaptee->display($this->template_dir . "/index.php");

case 'TWIG':
//обработка шаблона для TWIG
break;
}


Теперь все вроде как стало на свои места.

Спустя 1 час, 3 минуты, 43 секунды (6.09.2012 - 12:14) Oyeme написал(а):
Вынесите типы отдельно -как константы. ;)


const TEMPLATE_TYPE_SMARTY = 'SMARTY';
const TEMPLATE_TYPE_TWIG = 'TWIG';

Спустя 8 часов, 59 минут (6.09.2012 - 21:13) Лена написал(а):
И за константы спасибо )
Последний вопрос. Если я в родителе определяю свойство и использую его в конструкторе, как мне его переопределить в дочернем классе?
В Command я хочу, чтобы было private $adapter = false
В его наследниках - private $adapter = true
Это свойство используется в конструкторе:
if ($this->adapter)
$this->view = new TemplateView($registry,$adaptee);
else
$this->view= new View($registry);

Получается в конструктор родительского класса добавить еще один аргумент и в дочернем переопределить?

Спустя 11 часов, 23 минуты, 2 секунды (7.09.2012 - 08:36) Oyeme написал(а):
Выносите из конструктора логигу switch в отдельный метод из класа TemplateView .

Выносите всё что может меняться.Старайтесь делать всё независимо друг от друга.
Можно и так.

Я Вам советую по другому.
Создайте отдельный метод на уровне абстракции.

public function setAdapter($adapter = true){
$this->adapter = $adapter;
}

public function getAdapter(){
return $this->adapter;
}

Тем самым,в конструктор Вам не надо будет подавать его.Вы переопределяете его только тогда ,когда Вам это нужно.

Спустя 3 часа, 35 минут, 23 секунды (7.09.2012 - 12:11) Guest написал(а):
Цитата
Тем самым,в конструктор Вам не надо будет подавать его.Вы переопределяете его только тогда ,когда Вам это нужно.


В этом случае в корне не правильно.
Один объект один адаптер (драйвер). Инициализация через конструктор не плохой вариант, но переопределение на лету через bean методы это ерунда, чревато большими проблемами в коде. Допустим если переопределяется адаптер-драйвер шаблонизатора несколько раз в коде - это будет ж....

Лучший способ выделить всё это дело в абстрактную фабрику или фабрику Products и использовать статические методы, что повысит читаемость и отделит логику выбора и инстанцирования адаптера-драйвера от "клиента".
class FactoryProductsCategory
{
public static function getWithSmartyDriver(Registry $registry)
{
return new ProductsCategory(Registry $registry, 'SMARTY');
}
}

$prductsCategory = FactoryProductsCategory::getWithSmartyDriver(new Register());


Здесь мы избавляемся и от неказистых конструкций switch и тем самым даём не изменяемые драйвера, что даёт целостность и безопасность использования.
Ни в коем случае не используйте изменение адаптера методами
Цитата
Я Вам советую по другому.
Создайте отдельный метод на уровне абстракции.

Спустя 3 минуты, 9 секунд (7.09.2012 - 12:15) Guest написал(а):
А лучше конечно так
class FactoryProductsCategory
{
public static function getWithSmartyDriver(Registry $registry)
{
$driveTemplate = new Smarty();
return new ProductsCategory(Registry $registry, $driveTemplate);
}
}


$prductsCategory = FactoryProductsCategory::getWithSmartyDriver(new Register());

Спустя 3 минуты, 4 секунды (7.09.2012 - 12:18) Guest написал(а):
Цитата
Один объект один адаптер (драйвер). Инициализация через конструктор не плохой вариант, но переопределение на лету через bean методы это ерунда, чревато большими проблемами в коде. Допустим если переопределяется адаптер-драйвер шаблонизатора несколько раз в коде - это будет ж....


Это создаёт брешь для ошибок в коде программистами.

Спустя 4 часа, 29 минут, 37 секунд (7.09.2012 - 16:47) Dezigo написал(а):
Ну почему плохо, я советую лучше сделать так.
В адаптере разделить это на два класса
вот тут.


public function setAdapter($adapter){
if(!in_array(get_class($adapter),$this->adapter)) {
$this->adapter[get_class($adapter)] = $adapter;
}
}

Взять

public function getAdapter($adapter){
return $this->adapter[$adapter];
}


Использовать так:

$this->setAdapter(new Smarty());
или
$this->setAdapter(new Twig());


Взять
print_r($this->getAdapter('Twig')); // name of the class

И данные вы не потеряете, так как объект сохраниться , груба говоря в коллекции (можете переписать) и переключаться можете.
Код не тестировал, пишу сразу тут. Должно работать.

Спустя 43 минуты, 19 секунд (7.09.2012 - 17:31) Guest написал(а):
Во первых всё тот же метод $this->setAdapter(new Smarty()); требуется инкапсулировать в фабрику, так как "клиент" просто не должен знать и иметь возможность инстанцировать из вне объект драйвера.
Логичность переключения между драйверами шаблонизаторов это ещё оооочень спорная вещь и совершенно не нужная на протяжении "жизни" сеанса, так как опять же самому себе брешь в ошибках делать нет смысла. Если уже так приспичило лучше всего их отделять а не использовать один и тот же объект в одном врапере.
Во вторых,интересная ситуация. особенно в отладке получается, если будет инстанцировать сторонний разработчик не один раз, к как этого требует драйвер . а несколько на протяжении всего сеанса обработки запроса!
Например:
// Inpost инстанцировал первоначальный драйвер
// при чём заметьте, объект абстрактен, то есть может менять сущность по этому переменную нет смысла называть например $tmplSmarty
// так как после этого $this->setAdapter(new Twig()); это уже будет иной объект, читаемость улетает + разные методы по работе с api драйверов (вообщем масса ошибок открывается)

$this->tmp = $this->setAdapter(new Smarty());
// Куча кода, файлов
*********
// Дядя Федя меняет конфигурацию того же самого драйвера Smarty
$this->tmpl->config = бла бла

// Куча кода .... файлов
// Пришёл сторонний программист Dezigo поменял конфигурацию, при чём это должен знать что в данный момент используется
// драйвер Smarty иначе ошибка от PHP последует, что нет такого свойства у Twig (это к примеру)

$this->tmpl->config = бла бла

// Куча кода ..... файлов
// Пришёл Аз есмь Цар :) и всё на хрен порубал в капусту

$this->tmpl = $this->setAdapter(new Smarty());


Фабрика даёт исключение такой ошибки.
Если хочет человек драйвер с новыми данными он получает через фабрику и то опять же желательно (хотя как посмотреть) синглтоном драйвер реализовать,а то несколько потоков вывода это то же брешь для ошибок.


Спустя 21 минута, 56 секунд (7.09.2012 - 17:53) Лена написал(а):
Не в ту степь пошло обсуждение.
Я спрашивала не про адаптер, а про конструктор контроллера, у меня он Command. Его код - выше.
Есть в нем свойство private $adapter = true;, можно ли, чтобы в базовом классе оно было false, а в потомках - true. Об этом мой пост за 6.09.2012 - 18:13. Через setAdapter и getADapter не сильно понятно. Я делала вызов этих методов в конструкторе базового контроллера, ничего не меняется. Т.е. если делать так:

if ($this->getAdapter())
$this->view = new TemplateView($registry,$adaptee);
else
$this->view= new View($registry);



Хотя про адаптер тоже интересно получилось.
Слишком много switchей получается внутри самого класса адаптера. Обычно если такая ситуация, надо как-то связывать объекты по-другому.
Смотрите, приведу вариант адаптера, который уже оттестировала для Смарти:

class TemplateView extends View{

private $adaptee;
private $adapter;
const TEMPLATE_TYPE_NATIVE = 'NATIVE';
const TEMPLATE_TYPE_SMARTY = 'SMARTY';
const TEMPLATE_TYPE_TWIG = 'TWIG';

//подключение шаблонизатора
public function __construct($registry,$adaptee) {

parent::__construct($registry);
$this->registry = $registry;
$this->db = $this->registry->get('DB');

$this->theme = $this->getTheme();
$this->typetpl = $this->getTypeTemplate();

switch ($adaptee) {

case self::TEMPLATE_TYPE_NATIVE:
$this->adapter = self::TEMPLATE_TYPE_NATIVE;
$this->template_dir = PAGE_PATH . "/view/theme/" . $this->theme . "/template/native";
break;

case self::TEMPLATE_TYPE_SMARTY:

$this->adapter = self::TEMPLATE_TYPE_SMARTY;

$this->template_dir = PAGE_PATH . "view/theme/" . $this->theme . "/template/smarty";
require_once (PLUGINS_PATH . "smarty/Smarty.class.php");
$this->adaptee = new Smarty;

$this->adaptee->template_dir = $this->template_dir;
$this->adaptee->compile_dir = PAGE_PATH . "view/theme/" . $this->theme . "/template/smarty/templates_c/";
$this->adaptee->config_dir = PAGE_PATH . "view/theme/" . $this->theme . "/template/smarty/configs";
$this->adaptee->cache_dir = PAGE_PATH . "view/theme/" . $this->theme . "/template/smarty/cache";

break;

case self::TEMPLATE_TYPE_TWIG:
$this->adapter = self::TEMPLATE_TYPE_TWIG;
$this->template_dir = PAGE_PATH . "view/theme/" . $this->theme . "/template/twig";
require_once (PLUGINS_PATH . '/Twig-v1.9.2-8/lib/Twig/Autoloader.php');
Twig_Autoloader::register();
$loader = new Twig_Loader_Filesystem($this->template_dir);

$this->adaptee = new Twig_Environment($loader, array(
'cache' => PAGE_PATH . "view/theme/" . $this->theme . "/template/twig/cache",

));


break;

default:
$this->adapter = self::TEMPLATE_TYPE_NATIVE;
$this->template_dir = PAGE_PATH . "/view/theme/" . $this->theme . "/template/native";
break;
}

}



function fetch($template, $params = array()){

$_css = $js = $name = '';

switch ($this->adapter) {

case self::TEMPLATE_TYPE_NATIVE:
$this->typetpl = 'native';
$content = $this->fetchPartial($template, $params);
break;

case self::TEMPLATE_TYPE_SMARTY:
$content = '';
$this->typetpl = 'smarty';
$this->adaptee->assign('param',$params);
$this->adaptee->assign('content',$this->adaptee->fetch($template.".tpl"));
break;

case self::TEMPLATE_TYPE_TWIG:
//обработка шаблона для TWIG
$this->typetpl = 'twig';
break;
}

$arrTpl = $this->getHtmlMarkup($content);

switch ($this->adapter) {

case self::TEMPLATE_TYPE_NATIVE:
$out = $this->fetchPartial(PAGE_PATH . "view/theme/" . $this->theme . "/template/" . $this->typetpl . "/index", $arrTpl);
break;

case self::TEMPLATE_TYPE_SMARTY:

array_shift($arrTpl);
foreach($arrTpl as $k=>$v){

$this->adaptee->assign($k,$v);
}

$out = $this->adaptee->display(PAGE_PATH . "view/theme/" . $this->theme . "/template/" . $this->typetpl . "/index.tpl");

break;

case self::TEMPLATE_TYPE_TWIG:
//обработка шаблона для TWIG
break;
}

return $out;
}

function render($template, $params = array()){
switch ($this->adapter) {

case self::TEMPLATE_TYPE_NATIVE:
echo $this->fetch($template, $params);
break;

case self::TEMPLATE_TYPE_SMARTY:
case self::TEMPLATE_TYPE_TWIG:

return $this->fetch($template, $params);

break;
}
}
}


Спустя 24 минуты, 44 секунды (7.09.2012 - 18:17) Guest написал(а):
Цитата
Хотя про адаптер тоже интересно получилось.
Слишком много switchей получается внутри самого класса адаптера. Обычно если такая ситуация, надо как-то связывать объекты по-другому.

Поэтому всё что выше говорил и стоит сделать. Отделить инстанцирование и конфигурирование в отдельный класс фабрику по отдельным методам. Тогда сразу от switch избавитесь. Вообщем то фабрика это очень хорошо устраняет.

Спустя 6 часов, 19 минут, 40 секунд (8.09.2012 - 00:37) Guest написал(а):
Цитата
Не в ту степь пошло обсуждение.
Я спрашивала не про адаптер, а про конструктор контроллера, у меня он Command. Его код - выше.

Может и пошло из за не правильной архитектуры.
Сам контроллер Command говорит за себя, он управляет и инициирует команды и запуск контроллеров страниц.
Всё что связано с шаблонизаторами и и же с ним стоит отделить в окружение - environment, которое обеспечит корректное выполнение сценария запроса.

Спустя 1 минута, 43 секунды (8.09.2012 - 00:39) Guest написал(а):
Слишком до фига на себя берёт ответственности FrontController, от того и тяжело перераспределить обязанности по классам.
Быстрый ответ:

 Графические смайлики |  Показывать подпись
Здесь расположена полная версия этой страницы.
Invision Power Board © 2001-2024 Invision Power Services, Inc.