Встраивание своей классовой структуры в проект на CodeIgniter

от автора

Доброго времени суток, товарищи.

В этом посте расскажу о том, как обойти ограничения, которые накладывает фреймворк на разработчика, при этом оставив за собой возможность воспользоваться его функциональностью.

Я занимаюсь разработкой ресурса для кросс-постинга в социальные сети. Изначально продукт был предназначен только для Вконтакте и Facebook и для работы с API было выделено по одному контроллеры и по одной модели, плюс модель для работы с cURL. Пока была необходимость работать только с двумя социальными сетями такая классовая структура проекта не выглядела удручающей. Но стоило добавить работу ещё с несколькими соц. сетями, стало очевидно что такая модель ведёт к хаосу и полному бардаку как на стороне работы с API так и на стороне клиента. Чего стоит ветвление из 10 else if для просмотра данных пользователя или 10 ajax запросов для отправки сообщений в социальные сети. Было принято решение отрефакторить весь этот ужас, воспользовавшись паттерном Фабрика. Всё представлялось просто: описываем интерфейс с общим функционалом работы с API, делаем фабричный класс и единственный контроллер, который будет реквайрить фабричный класс. Но как только начали переносить функционал на новую парадигму, нас осенило. Вся работа в бд, пользовательскими данными, логами и https держится на CI моделях и библиотеках. Тут то я понял как был неправ, когда писал в курсовой что CodeIgniter не накладывает ограничений на разработчика — ещё как накладывает. Стоит немного шагнуть в своём решении за рамки модели MVC, возникает проблема — как включить это решение в проект.

На первый взгляд очевидным решением заэкстендить в классах соц. сетей и фабрики модели CI_model и работать, как обычно. Но так же было очевидна идеологическая неверность негибкость и такого подхода.

  • Во первых: даёт возможность грузить модели соц. сетей отдельно от фабричного класса. А значит в перспективе не достаточно ответственный аутсорсер или неразборчивый новичок этой возможностью воспользуются и вернётся весь хаос и бардак.
  • Во вторых: классы просто не должны содержать функционал моделей.

Но вместо того чтобы идти на поводу у фреймворка я решил поэксперементировать. Первым делом было решено вынести в отдельное поле объект класса CI_Loader. Но решение оказалось не слишком то удачным, так как требовало внесения измений в классы. Тогда попробовали вынесни в отдельное поле целую модель CI. Примерно вот так стала выглядель диаграмма классов.
image

Класс Framework — это обычная модель CI

class Framework extends CI_Model { 	 	/** 	* 	* @var stdObject $model коллекция ссылок на модели  	*/ 	public $model;  	/** 	* 	* @var stdObject $library коллекция ссылок на библиотеки 	*/ 	public $library;  	public __construct() { 		parent::__construct; 		$this->load->model('https'); 		$this->model->dx_auth = $this->dx_auth; 		$this->model->https = $this->https; 		$this->library->db = $this->db; 	} } 

И вуаля

class ACSocial { 	/** 	* 	*@var Framework ссылка на модель  	*/ 	public $framework;  	public function __construct() { 		$this->framework = new Framework(); ... 

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

$this->framework->model->db->get_where('users', array('id' => $id)); 

если необходимых моделек немного можно не выделять их в коллекции а запоминать отдельным полем класса Framework.

А далее фабричный метод просто включается в нужный контроллер или модель (я вынес require в helpers чтобы не портить внешний вид контроллера) и готово!
image

ссылка на оригинал статьи http://habrahabr.ru/post/178749/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *