читать дальше
Создадим абстрактный класс некого контроллера:
abstract class Controller { protected $_data = array(); protected $_chain = null; public function __construct(array $data = array()) { $this->_data = $data; } public function setChain(Handler $chain) { $this->_chain = $chain; } public function getChain() { return $this->_chain; } abstract public function runStrategy(); }
Теперь добавим набор унаследованных от него классов, реализующих разную интересную логику:
class D extends Controller { public function runStrategy() { echo 'I am just D!<br />'; printf('My data is: %s', print_r($this->_data, true)); } } class CA extends Controller { public function runStrategy() { echo '<table border="1">'; foreach ($this->_data as $item) { echo "<tr><td>{$item}</td></tr>"; } echo '</table>'; } } class CB extends Controller { public function runStrategy() { foreach ($this->_data as $item) { echo "{$item}<br />"; } } } class CC extends Controller { public function runStrategy() { foreach ($this->_data as $item) { echo "----{$item}<br />"; } } }
Напишем непосредственно реализацию цепочки:
class Handler { protected $_next = null; protected $_controller; public function getLimit() { return $this->limit; } public function __construct(Handler $handler = null) { $this->setNext($handler); } public function setNext(Handler $handler = null) { $this->_next = $handler; } public function getNext() { return $this->_next; } public function getController() { return $this->_controller; } public function setController(Controller $controller) { $this->_controller = $controller; } public function handleRequest($state = 0) { if ($state === 0) {echo 'START FK<BR />';} $this->_controller->runStrategy(); $state++; if ($this->_next) { $this->_next->handleRequest($state); } if ($state === 1) {echo 'STOP FK<BR />';} } }
В коде метода handleRequest показано, как можно реализовать выполнение каких-либо действие (у меня схематичное отключение и включение внешних ключей) до и после вызова всех методов.
Теперь создадим класс-контроллер, который внутри себя изменит цепочку:
class C extends Controller { public function runStrategy() { $cs = array(); for ($i = 0; $i < 2; $i++) { $c1 = new CA(array('word1'.$i, 'word2'.$i, 'word3'.$i, 'word4'.$i)); $c2 = new CB(array('Russia'.$i, 'USA'.$i, 'China'.$i, 'France'.$i)); $c3 = new CC(array('hi'.$i, 'bye'.$i, '9000'.$i, '!-^-!'.$i)); $cs['s'][] = $c1; $cs['m'][] = $c2; $cs['f'][] = $c3; } foreach ($cs as $k => $vs) { foreach ($vs as $v) { $cs['r'][] = $v; } } $cs = $cs['r']; $start = $this->getChain()->getNext();; foreach ($cs as $c) { $start = new Handler($start); $start->setController($c); } $this->getChain()->setNext($start); print_r($this->getChain()); } }
Конечно, print_r нужно убрать. Я оставил его, чтобы вы могли увидеть, какая цепочка получится.
Осталось добавить использование цепочки:
$cMain = new C(); $cAdditional = new D(); $cAdditional2 = new D(array('Second D')); $start = new Handler(); $start->setController($cAdditional2); $start = new Handler($start); $start->setController($cAdditional); $start = new Handler($start); $start->setController($cMain); $start->getController()->setChain($start); echo '<br />'; $start->handleRequest();
Полный код (по сути все то же, что тут) можно взять здесь: gist.github.com/1688458