Компоненты: перезагрузка
Не знаю, такую-ли ситуацию имел в виду BorisPlus в своем комментарии. Ну, чем богаты. Вообще не хотел это все описывать, потому как код довольно халтурно написан.
Этот код приложения, изначально крутившийся по Cake 1.1, был переписан для какой-то беты Cake 1.2. С текущей версией, 1.2.5, он работает без проблем, но, возможно, нуждается в чистке.
Эта часть программы выполняющий импорт данных от поставщиков. Поставщики предоставляют данные в CSV формате, но порядок колонок, некоторые значения и т.д., конечно разные. Для осмысленной обработки эти полученные данные надо привести к единообразному виду.
Данные поступают из написанного куцего Datasource, скармливанются компоненту, который и выполняет разбор и приведение к общему виду, потом записываются в нашу таблицу.
Компонент подгружается динамически, в зависимости от поставщика. Все компоненты являются наследниками базового и реализуют метод parse. Этот метод базового компонента, если не перегружен, возвращает NULL — в этом случае в нашу таблицу ничего не записываем, переходим к следующей порции данных. Соответственно методы наследников тоже могут возвращать NULL при ошибке разбора, например, при отсутствии какого-либо ключевого поля.
Еще базовый компонент содержит некоторое количество служебных методов, общих для всех, с целью унифицировать данные.
Увы, все файлы с компонентами находятся в каталоге components. Зато после перегрузки можно к загруженному компоненту обращаться по имени базового:
$this->SupplierCsv->parse($data);
В коде контроллера загружается базовый компонент. Так как он нужен только в одном методе контроллера, в нем я его и загружаю:
if (!App::import('Component', 'SupplierCsv')) die('Cannot load SupplierCsv component');
Еще у базового компонента есть метод factory. Я не помню, почему я его статическим объявил, честно. :-) Он получает в качестве параметра ссылку на контроллер и название компонента для обработки данных от конкретного поставщика:
SupplierCsvComponent::factory($this, array('CsvComponentName'=>$component_name));
Теперь методы базового компонента, SupplierCsvComponent:
function startup(&$controller) { $this->controller = $controller; $controller->SupplierCsv = $this; } static function factory(&$controller, $supplier) { App::import('Component', $supplier['CsvComponentName']); $componentclass = $supplier['CsvComponentName'] . 'Component'; $controller->SupplierCsv = new $componentclass; $controller->SupplierCsv->startup($controller); }
ну и код метода startup дочерних классов:
function startup(&$controller) { parent::startup($controller); $this->init = $this->name; }
Решение неидельное, наверняка можно соптимизировать. Мне, честно говоря, заниматься этим не хочется. Просто потому, что я в итоге начну вообще все с нуля переделывать и менять логику. :)
Откровенно говоря, огород можно было бы и не городить. Можно через App::import() загрузить класс компонента, а потом какой-нибудь переменной контроллера присвоить экземпляр этого класса.
Наверное, я раньше грузил компонент, указывая его в массиве $components, потому и сделал такую навернутую схему.
А может мне не хотелось require_once использовать… Ну не помню. :)
Update: Если соберусь переписывать, надо будет рефлексию попробовать использовать. :)
-
BorisPlus
-
BorisPlus
-
BorisPlus
-
Сергей



