Статьи

Продвинутые методы CodeIgniter и хитрости

CodeIgniter — это широко используемый фреймворк PHP, цель которого — помочь разработчикам написать более структурированный код и удалить стандартные задачи из рабочего процесса.

В этой статье я собираюсь объяснить некоторые невероятно полезные методы, которые можно использовать при разработке приложений с использованием CodeIgniter.


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

1
$value = $this->config->item( ‘some_item’ );

Это хорошо, если у нас есть только пара параметров конфигурации, но когда нам нужно извлечь дюжину параметров конфигурации или около того, загрузка значений таким способом может быть очень раздражающей. Разве не было бы здорово загрузить каждый параметр, например, массив, который мы используем в файле конфигурации? Для этого вам нужно загрузить его следующим образом.

1
2
3
$this->load->config( ‘config_file’, true );
$options = $this->config->item( ‘config_file’ );
// $options[‘some_item’];

И с этой единственной строкой весь наш файл конфигурации будет помещен в массив $options . И, чтобы еще больше подсластить сделку, использование этой техники также гарантирует, что вы избежите проблемы конфликта имен в файлах конфигурации. Таким образом, ваши параметры могут быть названы как угодно, не беспокоясь о других файлах конфигурации.


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

Чтобы сделать это, поместите приватный член _options в свою библиотеку и используйте конструктор, подобный следующему.

01
02
03
04
05
06
07
08
09
10
private $_options = array();
 
public function __construct( $options = array() ) {
    if ( is_empty( $options ) ) {
        $this->load->config( ‘config_file’, true );
        $options = $this->config->item( ‘config_file’ );
    }
     
    $this->_options = $options;
}

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


Необходимость отправлять электронные письма в формате HTML через ваше приложение вездесуще, будь то рассылка или какое-либо автоматическое приветственное сообщение. Обычно вы делаете это вручную, кодируя соответствующий HTML-код в параметре message нашего объекта электронной почты (это было сделано, это было сделано).

Ну, не секрет, что описанный выше метод довольно уродлив. Следующий совет — не совсем хитрость, а просто способ воспользоваться некоторыми функциями CodeIgniter там, где это имеет смысл.

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

В папке views вашего приложения создайте папку с именем emails и поместите в нее любое HTML-сообщение, которое вы хотите отправить, с соответствующей структурой, которая будет отображаться почтовыми клиентами. И теперь, в методе, где вы снимаете электронные письма, вы можете использовать следующий код:

1
2
3
4
5
6
7
8
public function send_mail() {
    $this->load->library( ’email’ );
    $this->email->from( ‘jdoe@gmail.com’, ‘John Doe’ );
    $this->email->to( ‘jane_doe@gmail.com’ );
    $this->email->subject( ‘Some subject’ );
    $this->email->message( $this->load->view( ’emails/message’, $data, true ) );
    $this->email->send();
}

Несколько важных вещей, которые следует иметь в виду при использовании этой техники:

  • Библиотека электронной почты должна быть настроена, чтобы иметь возможность отправлять электронные письма в формате HTML
  • Объект data используемый при загрузке представления, должен содержать параметры, используемые в представлении.
  • При таком подходе мы используем встроенную функциональность получения содержимого файла представления вместо отправки его в выходной класс, устанавливая для третьего параметра значение true при загрузке представления.

Посмотрим правде в глаза: почти каждое недавнее PHP-приложение — это бэкэнд-сервис или API. Если вы использовали API Карт Google, вы, вероятно, заметили, что Google позволяет нам передавать параметр версии, чтобы мы сообщали ему, какую версию мы будем использовать.

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

С помощью этой техники мы сможем использовать одну установку CodeIgniter для обработки нескольких версий нашего приложения с использованием одного и того же индексного файла. Мы сможем выбрать версию, передав параметр v в запросе.

Есть несколько вещей, чтобы это сработало. Прежде всего, я собираюсь переименовать папку своего application . Поскольку это первая версия моего API, я просто назову его 1.0.0. После этого я переименую свой файл index.php , назову его 1.0.0.php и изменим в нем строку application_folder . Заменить строку 75 следующим текстом:

1
$application_folder = ‘1.0.0’;

Круто, теперь наша версия приложения 1.0.0. Мы собираемся назвать этот файл 1.0.0.php вместо индекса? Точно нет! Давайте создадим новый файл index.php и добавим в него следующий код.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
define( ‘API_VER’, ‘v’ );
 
array_key_exists( API_VER, $_REQUEST ) ?
 
if ( file_exists( «{$v}.php» ) ) {
    if ( is_dir( dirname( __FILE__ ) . «/{$v}» ) ) {
        require dirname( __FILE__ ) .
    } else {
        $error = new stdClass();
        $error->error = true;
        $error->description = ‘INVALID_API_VERSION’;
        echo json_encode( $error );
        exit;
    }
} else {
    $error = new stdClass();
    $error->error = true;
    $error->description = ‘INVALID_API_VERSION’;
    echo json_encode( $error );
    exit;
}

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

Чтобы добавить больше версий, нам просто нужно скопировать нашу папку 1.0.0 и файл 1.0.0.php , переименовать их в соответствии с версией, которую мы собираемся создать, изменить переменную application_folder в файле и начать работать над следующая версия нашего API. Когда мы чувствуем себя достаточно комфортно с ним, мы можем сделать его версией, изменив файл index.php .


Точечная запись? Нет, я не говорю о сообщениях Objective-C. Если вы использовали API Twitter или что-то подобное, вы помните, что в конце вызова метода вы можете указать формат, в котором вы хотите получить ответ. Поскольку мне действительно нравится создавать сервисы RESTful с использованием CodeIgniter, я хотел бы добавить эта функциональность для них, хотя я всегда использую JSON.

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

Во-первых, что такое крючки? Согласно руководству пользователя CodeIgniter ,

Функция CodeIgniter Hooks предоставляет возможность подключаться и изменять внутреннюю работу фреймворка без взлома основных файлов.

Говоря простым языком, это способ изменить нормальный ход выполнения приложения. Хотя мы не хотим делать именно это здесь, мы хотим предварительно обработать наш URI, прежде чем класс CodeIgniter Router сможет его проверить. Имея это в виду, мы собираемся использовать хук «pre_system».

Чтобы мы могли использовать хуки, мы должны включить их. Для этого откройте файл config.php разделе config и установите для элемента enable_hooks значение true.

1
$config[‘enable_hooks’] = TRUE;

Теперь нам нужно добавить хук, который позаботится о процессе предварительной маршрутизации. Внутри папки config папке вашего приложения откройте файл hooks.php и добавьте следующий код:

1
2
3
4
5
6
$hook[‘pre_system’] = array(
    ‘class’ => ‘Router’,
    ‘function’ => ‘route’,
    ‘filename’ => ‘router.php’,
    ‘filepath’ => ‘hooks’
);

Этот код говорит нашему приложению, что нужно запустить метод route нашего класса Router внутри нашей папки hooks . Краткое замечание: параметр filepath — это путь к файлу, в котором есть метод, который вы хотите вызвать, и он ДОЛЖЕН быть относительно папки вашего приложения БЕЗ завершающего слеша.

Теперь нам нужно создать класс и метод, которые будет вызывать этот хук. В папке « hooks » (если ее там нет, создайте ее) внутри папки application , создайте новый файл, назовите его router.php и поместите в него следующий код.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
if ( !defined( ‘BASEPATH’ ) ) exit( ‘No direct script access allowed’ );
 
class Router {
     
    private static $_format = »;
     
    public function route() {
        $request = strstr( $_SERVER[‘REQUEST_URI’], ‘?’, true );
        if ( !$request ) {
            $request = $_SERVER[‘REQUEST_URI’];
        }
        $parts = explode( ‘.’, $request );
        self::$_format = $parts[ sizeof($parts) — 1 ];
         
        if ( self::$_format == ‘json’ || self::$_format == ‘xml’ || self::$_format == ‘rss’ || self::$_format == ‘atom’ ) {
            $_SERVER[‘REQUEST_URI’] = substr( $request, 0, ( strlen( $request ) — strlen( self::$_format ) — 1 ) );
        } else {
            self::$_format = »;
        }
    }
}

Функция CodeIgniter Hooks предоставляет возможность подключаться и изменять внутреннюю работу фреймворка без взлома основных файлов.

Несколько вещей, чтобы отметить здесь. Прежде всего, вы заметите, что я использую статический член класса для хранения типа запроса. Это потому, что мы правильно получаем формат ответа, но не можем сообщить об этом остальной части приложения. На этом раннем этапе выполнения приложения класс config еще не загружен, поэтому нам нужно использовать другую ловушку. Имея это в виду, нам нужно сделать его статичным, чтобы он не переопределялся при вызове следующего хука.

В самом начале я проверяю ? символ, поэтому изменение маршрута здесь не будет конфликтовать ни с какими параметрами, переданными через URL. Метод strstr будет возвращать строку ДО того символа, когда для третьего параметра задано значение true. Помните, что это поведение было добавлено в PHP 5.3.0, поэтому, если вы используете предыдущую версию, вам понадобится другой способ получить часть строки перед ? символ.

Из-за способа, которым мы извлекаем запрошенный формат ответа из URI, а затем вручную устанавливаем ключ REQUEST_URI для CodeIgniter Router, нам нужно проверить, что запрошенный вывод действителен. Если нет, мы позволяем приложению обрабатывать запрос без вмешательства.

Теперь мы определили запрошенный формат ответа, но наши контролеры не знают об этом. Я думаю, что чистый способ сообщить это с помощью параметра config . Чтобы установить его, нам нужно использовать другой крючок. Первые два хука — pre_system и pre_controller .

Однако на данный момент мы не можем использовать метод get_instance , то есть мы не можем установить элемент конфигурации, поэтому мы будем использовать хук post_controller_constructor . Пока вы не собираетесь использовать элемент конфигурации формата ответа в конструкторах контроллеров, этот метод будет работать.

После перехвата hooks.php файле hooks.php добавьте следующий код.

1
2
3
4
5
6
$hook[‘post_controller_constructor’] = array(
    ‘class’ => ‘Router’,
    ‘function’ => ‘config’,
    ‘filename’ => ‘router.php’,
    ‘filepath’ => ‘hooks’
);

Как вы можете сказать, эта ловушка вызывает другой метод из того же класса, который мы используем для получения запрошенного формата ответа. В классе Router после (или до) метода route добавьте следующий код.

1
2
3
4
public function config() {
    $CI =& get_instance();
    $CI->config->set_item( ‘response_format’, self::$_format );
}

В этом методе мы устанавливаем опцию конфигурации под названием response_format с форматом, полученным в методе route .

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

1
$format = $this->config->item( ‘response_format’ );

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


Я надеюсь, что вы нашли некоторые из этих советов полезными. Как вы, наверное, заметили, я сосредоточился на сервисах RESTful, поскольку, на мой взгляд, именно на них мы должны сосредоточиться, как на PHP-разработчиках.

Я с нетерпением жду ваших комментариев и большое спасибо за чтение.