Как создать пользовательские драйверы в CodeIgniter
Russian (Pусский) translation by Ilya Nikov (you can also view the original English article)
Работая в качестве разработчика CodeIgniter, вы могли бы познакомиться с концепцией библиотеки, которая обогащает функциональные возможности фреймворка, а сам CodeIgniter предоставляет множество полезных библиотек в ядре.
Аналогично, драйвер представляет собой особый вид библиотеки, который позволяет добавлять пользовательские функции, чтобы основной класс драйвера выполнял роль родительского класса, а адаптеры рассматривались как дочерние классы.
Лучший способ понять концепцию драйверов - посмотреть, как реализовано кэширование в CodeIgniter. Основной класс Cache действует как родительский класс и расширяет класс CI_Driver_Library. С другой стороны, вы в конечном итоге найдете дочерние классы для APC, Memcached, Redis и т.п., Реализованные в виде подключаемых адаптеров. Дочерние классы расширяют класс CI_Driver вместо основного класса драйвера.
Красота этого подхода заключается в том, что вы можете легко расширить функциональность драйвера, добавив новый адаптер по мере необходимости. Как и в случае кеширования, если вам нужно добавить пользовательскую стратегию кэширования, вы просто отступите от ее реализации в виде пользовательского адаптера.
Создание пользовательского драйвера в приложении CodeIgniter является целью сегодняшней статьи. В этом случае мы рассмотрим пример реального приложения, где мы создадим драйвер MediaRenderer, используемый для рендеринга мультимедиа из разных сервисов, таких как YouTube, Vimeo и т.д. Различные службы будут реализованы в виде классов адаптеров.
Настройка файлов
Имя драйвера, которое мы собираемся реализовать в этой статье, - MediaRenderer. Давайте быстро рассмотрим список файлов, необходимых для нужной настройки:
-
application/libraries/MediaRenderer/MediaRendererInterface.php
: Это интерфейс, который необходимо реализовать адаптеру. -
application/config/mediarenderer.php
: Файл конфигурации, в котором содержатся наши настраиваемые параметры, связанные с драйвером. -
application/libraries/MediaRenderer/MediaRenderer.php
: Это класс, который расширяет CI_Driver_Library и используется для управления различными адаптерами, доступными в приложении. -
application/libraries/MediaRenderer/drivers/ MediaRenderer_youtube.php
: Это класс, который реализует адаптер YouTube. -
application/libraries/MediaRenderer/drivers/MediaRenderer_vimeo.php
: Это класс, который реализует адаптер Vimeo. -
application/controllers/Media.php
: Это класс контроллера, который мы реализуем, чтобы продемонстрировать использование нашего пользовательского драйвера.
Итак, это список файлов, которые мы собираемся реализовать в этой статье.
Создание драйверов
В этом разделе мы создадим базовые файлы нашего пользовательского драйвера.
Первое, что нам нужно сделать, это определить файл конфигурации нашего пользовательского драйвера. Давайте определим файл application/config/mediarenderer.php
, как показано ниже.
1 |
<?php
|
2 |
$config['media_services'] = array('youtube', 'vimeo'); |
3 |
$config['media_default'] = 'youtube'; |
Это означает, что мы собираемся реализовать два адаптера - YouTube и Vimeo. Адаптер по умолчанию установлен на YouTube.
Далее создайте application/libraries/MediaRenderer/MediaRendererInterface.php
со следующим содержимым.
1 |
<?php
|
2 |
defined('BASEPATH') OR exit('No direct script access allowed'); |
3 |
|
4 |
/**
|
5 |
* MediaRendererInterface
|
6 |
*/
|
7 |
interface MediaRendererInterface |
8 |
{
|
9 |
public function display($id); |
10 |
}
|
Как вы можете видеть, это довольно простой интерфейс, который гарантирует, что адаптер, реализующий этот интерфейс, должен реализовать метод отображения.
Затем давайте посмотрим на файл драйвера MediaRenderer
. Далее создайте application/libraries/MediaRenderer/MediaRenderer.php
со следующим содержимым.
1 |
<?php
|
2 |
if ( ! defined('BASEPATH')) exit('No direct script access allowed'); |
3 |
interface_exists('MediaRendererInterface', FALSE) OR require_once(APPPATH.'/libraries/MediaRenderer/MediaRendererInterface.php'); |
4 |
|
5 |
/**
|
6 |
* MediaRenderer Class
|
7 |
*/
|
8 |
class MediaRenderer extends CI_Driver_Library { |
9 |
|
10 |
public $valid_drivers; |
11 |
public $CI; |
12 |
protected $_adapter = 'youtube'; |
13 |
|
14 |
/**
|
15 |
* Class constructor
|
16 |
*/
|
17 |
public function __construct() |
18 |
{
|
19 |
$this->CI =& get_instance(); |
20 |
$this->CI->config->load('mediarenderer'); |
21 |
$this->valid_drivers = $this->CI->config->item('media_services'); |
22 |
$this->_adapter = $this->CI->config->item('media_default'); |
23 |
}
|
24 |
|
25 |
/**
|
26 |
* Overrided __get method to check if the adapter implements MediaRendererInterface interface
|
27 |
* @see CI_Driver_Library::__get()
|
28 |
*/
|
29 |
public function __get($child) |
30 |
{
|
31 |
if (in_array($child, $this->valid_drivers)) |
32 |
{
|
33 |
$object = $this->load_driver($child); |
34 |
|
35 |
if ($object instanceof MediaRendererInterface) |
36 |
{
|
37 |
return $object; |
38 |
}
|
39 |
else
|
40 |
{
|
41 |
show_error("MediaRenderer: Adapter '".$child."' doesn't implement MediaRendererInterface. Aborting."); |
42 |
return; |
43 |
}
|
44 |
}
|
45 |
else
|
46 |
{
|
47 |
show_error('Unable to load the requested adapter: '.$child); |
48 |
return; |
49 |
}
|
50 |
}
|
51 |
|
52 |
/**
|
53 |
* @param string $adapter Adapter name
|
54 |
* @return MediaRenderer
|
55 |
*/
|
56 |
public function setAdapter($adapter) |
57 |
{
|
58 |
$this->_adapter = $adapter; |
59 |
return $this; |
60 |
}
|
61 |
|
62 |
/**
|
63 |
* @param string $id Media ID
|
64 |
*/
|
65 |
public function display($id) |
66 |
{
|
67 |
return $this->{$this->_adapter}->display($id); |
68 |
}
|
69 |
|
70 |
}
|
В начале файла мы добавляем интерфейс MediaRendererInterface
, который мы уже определили ранее в этом разделе.
В соответствии со стандартами драйвера CodeIgniter наш класс MediaRenderer
расширяет класс CI_Driver_Library
, который позволяет легко получить доступ к адаптерам драйверов, используя метод load_driver
, определенный в классе CI_Driver_Library
.
Затем давайте посмотрим на конструктор.
1 |
public function __construct() |
2 |
{
|
3 |
$this->CI =& get_instance(); |
4 |
$this->CI->config->load('mediarenderer'); |
5 |
$this->valid_drivers = $this->CI->config->item('media_services'); |
6 |
$this->_adapter = $this->CI->config->item('media_default'); |
7 |
}
|
Вспомните файл конфигурации mediarenderer, который мы определили ранее, и это точно загружено в конструкторе в первую очередь. Необходимо, чтобы вы установили список адаптеров, которые поддерживаются драйвером, в свойство valid_drivers
, поэтому мы просто это и сделали. И, наконец, для удобства мы установили значение драйвера по умолчанию для свойства _adapter
.
Двигаясь дальше, давайте рассмотрим код метода __get
.
1 |
public function __get($child) |
2 |
{
|
3 |
if (in_array($child, $this->valid_drivers)) |
4 |
{
|
5 |
$object = $this->load_driver($child); |
6 |
|
7 |
if ($object instanceof MediaRendererInterface) |
8 |
{
|
9 |
return $object; |
10 |
}
|
11 |
else
|
12 |
{
|
13 |
show_error("MediaRenderer: Adapter '".$child."' doesn't implement MediaRendererInterface. Aborting."); |
14 |
return; |
15 |
}
|
16 |
}
|
17 |
else
|
18 |
{
|
19 |
show_error('Unable to load the requested adapter: '.$child); |
20 |
return; |
21 |
}
|
22 |
}
|
Я бы сказал, что вы не обязаны переопределять этот метод, и наш драйвер будет работать отлично, и без него. Причиной внедрения этого метода в нашем случае является обеспечение реализации интерфейса MediaRendererInterface
, и поэтому он будет следить за тем, чтобы каждый драйвер должен реализовать метод display.
Затем давайте посмотрим на метод setAdapter
.
1 |
public function setAdapter($adapter) |
2 |
{
|
3 |
$this->_adapter = $adapter; |
4 |
return $this; |
5 |
}
|
Как вы можете видеть, он просто используется для переопределения настроек адаптера по умолчанию, если вы хотите использовать другой адаптер в настоящее время.
Наконец, есть метод display
, который вызывает метод отображения соответствующего адаптера.
1 |
public function display($id) |
2 |
{
|
3 |
return $this->{$this->_adapter}->display($id); |
4 |
}
|
Опять же, я бы сказал, что вы можете пропустить реализацию этого метода, поскольку вы всегда можете вызвать метод отображения адаптера напрямую, как мы увидим далее в этой статье. Тем не менее, я хотел бы получить доступ к адаптерам с помощью метода отображения класса MediaRenderer
, поскольку это место, где вы могли бы реорганизовать общий код, который может реализовать адаптер.
Таким образом, в вашем распоряжении был класс MediaRenderer
.
Создаем адаптеры
Некоторое время мы обсуждали адаптеры драйверов, и теперь пришло время их реализовать.
Начнем с файла адаптера YouTube в приложении application/libraries/MediaRenderer/drivers/MediaRenderer_youtube.php.
1 |
<?php
|
2 |
if ( ! defined('BASEPATH')) exit('No direct script access allowed'); |
3 |
|
4 |
/**
|
5 |
* MediaRenderer_youtube Class
|
6 |
*/
|
7 |
class MediaRenderer_youtube extends CI_Driver implements MediaRendererInterface { |
8 |
|
9 |
/**
|
10 |
* @param string $id Media ID
|
11 |
* @see MediaRendererInterface::display()
|
12 |
*/
|
13 |
public function display($id) |
14 |
{
|
15 |
if ($id) |
16 |
{
|
17 |
return '<iframe width="420" height="315" src="//www.youtube.com/embed/'.$id.'" frameborder="0" |
18 |
allowfullscreen></iframe>'; |
19 |
}
|
20 |
}
|
21 |
|
22 |
}
|
Важно отметить, что имя адаптера имеет префикс MediaRenderer_
, а также расширяет класс CI_Driver
. Кроме того, он реализует интерфейс MediaRendererInterface
, чтобы убедиться, что мы придерживаемся стандартов, которые мы обсуждали ранее.
Причина, по которой наш класс адаптера расширяет класс CI_Driver
, заключается в использовании всех родительских методов и свойств. Вы правильно расслышали, вы можете получить доступ к методам и свойствам класса MediaRenderer
из класса MediaRenderer_youtube
, даже если он не распространяется непосредственно на класс MediaRenderer
.
Кроме того, довольно легко понять реализацию метода display
, который возвращает код вставки при условии, что медиа-идентификатор передается в качестве аргумента метода.
Класс адаптера Vimeo довольно похож на класс YouTube. Идем дальше и создаем его в application/libraries/MediaRenderer/drivers/MediaRenderer_vimeo.php
.
1 |
<?php
|
2 |
if ( ! defined('BASEPATH')) exit('No direct script access allowed'); |
3 |
|
4 |
/**
|
5 |
* MediaRenderer_vimeo Class
|
6 |
*/
|
7 |
class MediaRenderer_vimeo extends CI_Driver implements MediaRendererInterface { |
8 |
|
9 |
/**
|
10 |
* @param string $id Media ID
|
11 |
* @see MediaRendererInterface::display()
|
12 |
*/
|
13 |
public function display($id) |
14 |
{
|
15 |
if ($id) |
16 |
{
|
17 |
return '<iframe width="420" height="247" src="//player.vimeo.com/video/'.$id.'"></iframe>'; |
18 |
}
|
19 |
}
|
20 |
|
21 |
}
|
И на этом заканчиваем обсуждение адаптеров.
Все вместе
В последних разделах мы обсудили классы драйверов и адаптеров. В этом разделе, который является последним в этой статье, мы продолжим наше путешествие, чтобы пройти демонстрацию основного использования драйверов.
Начнем с создания файла контроллера application/controllers/Media.php
.
1 |
<?php
|
2 |
defined('BASEPATH') OR exit('No direct script access allowed'); |
3 |
|
4 |
/**
|
5 |
* Media Controller Class
|
6 |
*/
|
7 |
class Media extends CI_Controller { |
8 |
public function index() |
9 |
{
|
10 |
// this will use default adapter as per the config file
|
11 |
$this->load->driver('mediaRenderer'); |
12 |
|
13 |
// IMP: it must be a lowercase drivername when you use it
|
14 |
echo $this->mediarenderer->display("0GfCP5CWHO0"); |
15 |
|
16 |
// override adapter settings by setting it explicitly
|
17 |
echo $this->mediarenderer->setAdapter('vimeo')->display("225434434"); |
18 |
|
19 |
// access the adapter directly
|
20 |
echo $this->mediarenderer->vimeo->display("225434434"); |
21 |
echo $this->mediarenderer->youtube->display("0GfCP5CWHO0"); |
22 |
}
|
23 |
}
|
Первое, что нам нужно сделать, это загрузить наш собственный драйвер mediaRenderer
, и это то, что делает следующий фрагмент.
1 |
$this->load->driver('mediaRenderer'); |
Чтобы получить доступ к только что загруженному пользовательскому драйверу, вы должны использовать синтаксис $this->mediarenderer
. Важно отметить, что имя драйвера указано в нижнем регистре, независимо от фактического имени драйвера.
Затем давайте рассмотрим, что делает следующий код.
1 |
echo $this->mediarenderer->display("0GfCP5CWHO0"); |
Он вызывает метод display
класса MediaRenderer
в первую очередь, поскольку он делегирует элемент управления методу display
соответствующего адаптера, установленного в качестве адаптера по умолчанию в файле конфигурации медиаредактора. В конце концов, он делает вызов метода display
адаптера YouTube, поскольку в нашем случае это адаптер по умолчанию.
С другой стороны, если вы хотите вызвать метод display любого конкретного адаптера, вы всегда можете сделать это явно, как показано в следующем фрагменте.
1 |
echo $this->mediarenderer->setAdapter('vimeo')->display("225434434"); |
Как я уже упоминал ранее, вы также можете напрямую вызвать метод display
любого конкретного адаптера, не пройдя метод отображения класса MediaRenderer
.
1 |
echo $this->mediarenderer->vimeo->display("225434434"); |
2 |
echo $this->mediarenderer->youtube->display("0GfCP5CWHO0"); |
Таким образом, вы должны вызвать драйвер и его адаптеры рядом - благодаря структуре драйвера, которая позволяет вам подключать новые адаптеры «на лету» по мере необходимости.
И на этом все. Я надеюсь, что вам понравилась статья, и вы всегда можете попасть в раздел комментариев, чтобы выразить свои мысли и проблемы.
Заключение
Путешествие по драйверам фреймворка CodeIgniter было темой сегодняшней статьи.
Как всегда, статья начиналась с базового введения в концепцию драйверов фреймворка CodeIgniter. Как я и обещал, мы продолжили создание пользовательского драйвера на основе реального использования, и я считаю, что это лучший способ понять новую концепцию.
Мне бы очень хотелось услышать, если бы вы могли придумать что-нибудь об этой захватывающей концепции!