Статьи

Как создать менеджер макетов с помощью CodeIgniter

В этой статье о видео и сопутствующих материалах Premium вы узнаете, как создать простую, но мощную библиотеку для обработки макетов в популярной среде CodeIgniter Framework. Библиотека, которую вы создадите, позволит вам максимизировать свою эффективность, сэкономить время и код, модулировать ваши представления и даже ваши файлы Javascript и CSS.


Для этого урока все, что вам понадобится, это платформа CodeIgniter 1.7.2. Вы можете скачать его с их сайта по адресу codeigniter.com/downloads/


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

Идея состоит в том, чтобы имитировать вызовы $this->load->view(). Когда мы вызываем этот метод, мы передаем имя (и местоположение) нашего представления, а затем массив данных, которые будут доступны из представления. Вот пример:

1
2
3
4
function method($url_param)
{
  $this->load->view(‘controller_views/method_view’, array(‘url_param’ => $url_param));
}

Приведенный выше код возьмет файловую system/application/views/controller_views/method_view.php , передаст ей переменную url_param и затем отправит ее в браузер. Здесь мы и пришли. Мы пока не будем отправлять контент в браузер. Вместо этого мы отправим его в макет, а затем в браузер. Но как нам это сделать?

Методу view() который мы только что вызвали, можно передать третий (логический) параметр, который, если он равен true, будет возвращать визуализированное представление вместо отправки его в браузер. Мы можем сохранить этот контент, выполнить второй вызов того же метода, но на этот раз вызвать файл макета, который будет печатать этот контент (окруженный всеми верхними, нижними и нижними колонтитулами).



Мы создадим эту библиотеку шаг за шагом, начиная с самых простых. Прежде всего, мы создадим новую библиотеку в нашей папке system / application / library и назовем ее Layouts .

Если вы никогда не создавали библиотеку CodeIgniter, это просто классы, которые загружаются при вызове $this->load->library() .

Итак, давайте прыгнем прямо в код:

1
2
3
4
5
6
7
8
9
<?php if ( ! defined(‘BASEPATH’)) exit(‘No direct script access allowed’);
  
/**
 * Layouts Class.
 *
 */
class Layouts {
  public function __construct() { }
}

Давайте пройдемся по каждому разделу кода:

  1. Самая первая строка представляет собой соглашение о кодировании CodeIgniter, оно по существу гарантирует, что пользователи не смогут напрямую обращаться к файлу из своих браузеров, потому что CodeIgniter устанавливает константу BASEPATH в своем файле index.php .
  2. Класс будет только PHP 5. Это позволит нам добавить цепочку методов в класс, что будет полезно позже, когда мы будем работать с JS и CSS.
  3. Конструктор класса пока ничего не имеет. Это всего лишь скелет нашей библиотеки.

Итак, что произойдет, если мы включим это из controller ? Ну ничего. Класс пока ничего не делает (даже конструктор), поэтому ничего не произойдет.


Мы создадим очень простой макет, чтобы объяснить, как все работает.

1
2
3
4
5
6
7
8
9
<!DOCTYPE HTML>
<html>
<head>
  <title>Our very first layout!</title>
</head>
<body>
  <?php echo $content_for_layout;
</body>
</html>

Как видите, это чрезвычайно просто; это просто название и тело. Теперь важная часть находится в коде PHP там. Мы $content_for_layout переменную $content_for_layout . Идея состоит в том, чтобы назначить отображаемый контент этой переменной. Таким образом, он будет напечатан там, окружен остальным телом, головой и т. Д.


Давайте напишем некоторый код для обработки этого макета:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php if ( ! defined(‘BASEPATH’)) exit(‘No direct script access allowed’);
  
/**
 * Layouts Class.
 *
 */
class Layouts {
    
  // Will hold a CodeIgniter instance
  private $CI;
    
  public function __construct()
  {
    $this->CI =& get_instance();
  }
    
  public function view($view_name, $params = array(), $layout = ‘default’)
  {
    // Load the view’s content, with the params passed
    $view_content = $this->CI->load->view($view_name, $params, TRUE);
  
    // Now load the layout, and pass the view we just rendered
    $this->CI->load->view(‘laytous/’ . $layout, array(
      ‘content_for_layout’ => $view_content
    ));
  }
}

Давайте объясним, как выглядит новый код:

  1. Мы добавили новый закрытый атрибут в нашу библиотеку: $CI . Из наших библиотек мы не можем получить доступ к экземпляру CodeIgniter напрямую. Единственный способ — получить ссылку на него и получить к нему доступ оттуда. Итак, в нашем конструкторе (который вызывается при загрузке библиотеки) мы получаем наш экземпляр CI и назначаем его нашему локальному частному атрибуту $CI , чтобы мы могли вызвать его позже. Нам нужно вызвать метод load->view() .
  2. Теперь мы добавили метод просмотра. Синтаксис практически идентичен методу load->view() . Мы получаем имя представления, массив параметров (переменные, которые будут видны из представления) и имя макета, которое по умолчанию будет (duh) ‘default’. Последнее позволяет нам иметь несколько макетов в нашем приложении (возможно, один для поля входа без меню и прочего).
  3. Теперь, как мы говорили ранее, мы вызываем метод load->view() , передаем имя представления, параметры и третий параметр со значением TRUE . Это гарантирует, что мы не будем отправлять вывод в браузер. Вместо этого он будет возвращен нам и назначен переменной $view_content .
  4. Наконец, мы загружаем файл макета (который мы будем хранить в папке system/application/views/layouts ) и передаем содержимое только что загруженного представления в качестве параметра. Когда макет будет загружен, переменная $content_for_layout будет заменена только что загруженным содержимым и будет отправлена ​​в браузер (обратите внимание на отсутствующий конечный параметр, на этот раз мы не передаем TRUE ).

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

На самом деле название макета всегда одинаково. Это не практично. Мы должны иметь возможность легко изменить его с наших контроллеров, не создавая бесконечное количество макетов с разными заголовками (это противоречило бы цели этого урока). Итак, как мы это сделаем? Предположим, у сайта есть постоянное название, скажем, «Библиотека раскладок». После этого мы разместим раздел сайта, который мы посещаем. Например, для страницы входа заголовок будет выглядеть как «Библиотека раскладок | Вход в систему».

Во-первых, давайте немного перепишем макет.

1
2
3
4
5
6
7
8
9
<!DOCTYPE HTML>
<html>
<head>
  <title>Layouts Library<?php echo $title_for_layout ?></title>
</head>
<body>
  <?php echo $content_for_layout;
</body>
</html>

Мы только что добавили еще одно echo PHP. На этот раз мы $title_for_layout переменную $title_for_layout , которую мы $title_for_layout в нашей библиотеке. Вот переписанная библиотека:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<?php if ( ! defined(‘BASEPATH’)) exit(‘No direct script access allowed’);
  
/**
 * Layouts Class.
 *
 */
class Layouts {
    
  // Will hold a CodeIgniter instance
  private $CI;
    
  // Will hold a title for the page, NULL by default
  private $title_for_layout = NULL;
    
  // The title separator, ‘ |
  private $title_separator = ‘ |
    
  public function __construct()
  {
    $this->CI =& get_instance();
  }
    
  public function set_title($title)
  {
    $this->title_for_layout = $title;
  }
    
  public function view($view_name, $params = array(), $layout = ‘default’)
  {
    // Handle the site’s title.
    // separator and append the title.
    if ($this->title_for_layout !== NULL)
    {
      $separated_title_for_layout = $this->title_separator .
    }
      
    // Load the view’s content, with the params passed
    $view_content = $this->CI->load->view($view_name, $params, TRUE);
  
    // Now load the layout, and pass the view we just rendered
    $this->CI->load->view(‘laytous/’ . $layout, array(
      ‘content_for_layout’ => $view_content,
      ‘title_for_layout’ => $separated_title_for_layout
    ));
  }
}

Что мы здесь сделали?

  1. Мы добавили два новых атрибута в нашу библиотеку: $title_for_layout и $title_separator. Первый будет содержать наш заголовок, а второй будет определять строку, которая будет отделять заголовок макета от заголовка, установленного методом set_title() .
  2. Так как $title_for_layout был установлен как private, мы добавляем метод для его установки с наших контроллеров. Таким образом, set_title() установит значение $title_for_layout тому, что мы скажем, например. ‘Авторизоваться’.
  3. В методе view() мы добавили кусок кода для обработки нового атрибута. Если пользователь никогда не устанавливает заголовок для страницы, мы хотим иметь возможность «изящно ухудшать», т.е. не добавлять разделитель ни за что. Таким образом, мы сначала проверяем значение атрибута $title_for_layout . Если не NULL , тогда мы добавляем настроенный разделитель и заголовок, установленный методом set_title() .
  4. При рендеринге макета мы обязательно передаем новый атрибут (даже если NULL), чтобы мы могли отобразить его в заголовке.

Теперь, наконец, мы хотим иметь возможность добавлять файлы CSS и Javascript модульно. Что это значит? Скажем, вы хотите использовать плагин jQuery, но вы просто хотите использовать его в одной части веб-сайта (возможно, плагин для проверки формы). Вы можете просто включить его в само представление, но в конечном коде это выглядит не очень хорошо. Всегда желательно, чтобы все Javascript (и CSS) включались в header . Мы собираемся создать метод (ну, на самом деле, два), который позволит нам сделать именно это.

Давайте добавим эти два метода в вашу библиотеку:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public function add_include($path, $prepend_base_url = TRUE)
{
  if ($prepend_base_url)
  {
    $this->CI->load->helper(‘url’);
    $this->file_includes[] = base_url() .
  }
  else
  {
    $this->file_includes[] = $path;
  }
    
  return $this;
}
  
public function print_includes()
{
  // Initialize a string that will hold all includes
  $final_includes = »;
    
  foreach ($this->includes as $include)
  {
    // Check if it’s a JS or a CSS file
    if (preg_match(‘/js$/’, $include))
    {
      // It’s a JS file
      $final_includes .= ‘<script type=»text/javascript» src=»‘ . $include . ‘»></script>’;
    }
    elseif (preg_match(‘/css$/’, $include))
    {
      // It’s a CSS file
      $final_includes .= ‘<link href=»‘ . $include . ‘» rel=»stylesheet» type=»text/css» />’;
    }
      
    return $final_includes;
  }
}

Не забудьте также добавить этот новый атрибут в свой класс, чуть выше constructor :

1
private $includes = array();

и это к вашему макету, сразу после заголовка

1
<?php echo $this->layouts->print_includes() ?>

Небольшое объяснение:

  1. Метод add_include() позволяет нам добавлять несколько файлов JS или CSS из нашего controller . Он даже допускает цепочку методов, то есть мы можем сделать что-то вроде $this->layouts->add_include('js/jquery.js')->add_include('js/jquery.plugin.js')->add_include('css/jquery.plugin.css'); что может быть очень удобно при загрузке нескольких вещей. Эта функция цепочки методов является причиной, по которой нам нужен PHP 5, потому что PHP 4 не поддерживает его.
  2. Параметр $prepend_base_url в add_include() по умолчанию будет предшествовать базовому URL-адресу установки CodeIgniter. $prepend_base_url этот метод с $prepend_base_url установленным в FALSE , мы можем включить удаленные файлы (например, $prepend_base_url jQuery из CDN Google).
  3. Метод print_includes() пояснений. Он просматривает все включения, добавленные с помощью add_include() , проверяет, является ли файл Javascript или CSS-файлом (другие файлы не поддерживаются), и добавляет включение в строку, которая в конечном итоге будет отображена в макете.

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

Это окончательный код для макета и библиотеки:

01
02
03
04
05
06
07
08
09
10
<!DOCTYPE HTML>
<html>
<head>
  <title>Layouts Library<?php echo $title_for_layout ?></title>
  <?php echo $this->layouts->print_includes();
</head>
<body>
  <?php echo $content_for_layout;
</body>
</html>
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
<?php if ( ! defined(‘BASEPATH’)) exit(‘No direct script access allowed’);
  
/**
 * Layouts Class.
 *
 */
class Layouts {
    
  // Will hold a CodeIgniter instance
  private $CI;
    
  // Will hold a title for the page, NULL by default
  private $title_for_layout = NULL;
    
  // The title separator, ‘ |
  private $title_separator = ‘ |
    
  public function __construct()
  {
    $this->CI =& get_instance();
  }
    
  public function set_title($title)
  {
    $this->title_for_layout = $title;
  }
    
  public function view($view_name, $params = array(), $layout = ‘default’)
  {
    // Handle the site’s title.
    // separator and append the title.
    if ($this->title_for_layout !== NULL)
    {
      $separated_title_for_layout = $this->title_separator .
    }
      
    // Load the view’s content, with the params passed
    $view_content = $this->CI->load->view($view_name, $params, TRUE);
  
    // Now load the layout, and pass the view we just rendered
    $this->CI->load->view(‘laytous/’ . $layout, array(
      ‘content_for_layout’ => $view_content,
      ‘title_for_layout’ => $separated_title_for_layout
    ));
  }
    
  public function add_include($path, $prepend_base_url = TRUE)
  {
    if ($prepend_base_url)
    {
      $this->CI->load->helper(‘url’);
      $this->file_includes[] = base_url() .
    }
    else
    {
      $this->file_includes[] = $path;
    }
  
    return $this;
  }
  
  public function print_includes()
  {
    // Initialize a string that will hold all includes
    $final_includes = »;
  
    foreach ($this->includes as $include)
    {
      // Check if it’s a JS or a CSS file
      if (preg_match(‘/js$/’, $include))
      {
        // It’s a JS file
        $final_includes .= ‘<script type=»text/javascript» src=»‘ . $include . ‘»></script>’;
      }
      elseif (preg_match(‘/css$/’, $include))
      {
        // It’s a CSS file
        $final_includes .= ‘<link href=»‘ . $include . ‘» rel=»stylesheet» type=»text/css» />’;
      }
  
      return $final_includes;
    }
  }
}

Обязательно смотрите скринкаст для полного обзора и комментариев!