Пользовательские контроллеры в OpenCart 2
18 Мар 2023г. в 15:45Почему пользовательский контроллер?
Кое-что, что вы можете спросить в первую очередь — почему именно пользовательский контроллер? Давайте разберёмся как можно быстрее, что такое контроллер в OpenCart, прежде чем мы им займемся.
В контексте OpenCart контроллер является незаменимым компонентом фреймворка, который напрямую связан с процессом маршрутизации и отображает пользовательский интерфейс. В этом процессе он связывается с другими важными компонентами, такие как язык, модель и представление, чтобы выстроить окончательный результат.
Когда вы открываете доступ к любой странице OpenCart, фреймворк OpenCart ищет соответствующий контроллер и делегирует его дальнейшую обработку. Будучи модульным по своей природе, фреймворк OpenCart предоставляет несколько контроллеров, которые связаны с логически сгруппированными функциональными возможностями.
Например, группа учетных записей содержит контроллеры, которые связаны с логином, регистрацией, профилем и аналогичными вариантами использования. Точно так же, контрольная группа контроллеров обрабатывает процесс создания заказа.
В двух словах, когда нужно создать функцию, которая не находится в ядре OpenCart, и, если она использует новый URL-адрес в терминологии OpenCart, нужно перейти на пользовательский контроллер. Он даст полный контроль над процессом создания страницы — и тем, какие элементы вы хотите отобразить на странице.
Создание пользовательского контроллера
Сегодня мы реализуем базовую функциональность Guestbook, которая демонстрирует концепцию пользовательских контроллеров. В процессе этого мы создадим интерфейс во front-end, который позволит гостевым пользователям отправлять свои отзывы, введя их имя и текст сообщения.
Прежде чем продолжить, убедитесь, что у вас установлена рабочая версия OpenCart 2.3.x. Этого более чем достаточно, чтобы начать работу над функцией Guestbook.
Для тех, кто не знаком со структурой OpenCart, нужно искать front-end контроллеры в catalog/controller. Это каталог, который управляет всеми контроллерами по группам, основываясь на предоставляемых функциях.
В нашем случае мы создадим отдельную группу под названием guestbook. Затем создадим каталог catalog/controller/guestbook. Внутри этого каталога создадим entry.php файл со следующим содержимым. Это файл контроллера, который обрабатывает логику приложения и отправки функций гостевой книги.
<?php
class ControllerGuestbookEntry extends Controller {
private $error = array();
public function index() {
$this->load->language('guestbook/guestbook');
$this->document->setTitle($this->language->get('heading_title'));
if (($this->request->server['REQUEST_METHOD'] == 'POST') && $this->validate()) {
$this->load->model('guestbook/guestbook');
$data['subject'] = sprintf('New guestbook entry submitted by %s', $this->request->post['guest_name']);
$data['message'] = $this->request->post['guest_message'];
$this->model_guestbook_guestbook->processGuestbookEntry($data);
$this->session->data['success'] = $this->language->get('text_success');
$this->response->redirect($this->url->link('guestbook/entry', '', true));
}
$data['success'] = '';
if (isset($this->session->data['success'])) {
$data['success'] = $this->session->data['success'];
unset($this->session->data['success']);
}
$data['breadcrumbs'] = array();
$data['breadcrumbs'][] = array(
'text' => $this->language->get('text_home'),
'href' => $this->url->link('common/home')
);
$data['breadcrumbs'][] = array(
'text' => $this->language->get('heading_title'),
'href' => $this->url->link('guestbook/entry', '', true)
);
$data['heading_title'] = $this->language->get('heading_title');
$data['entry_guest_name'] = $this->language->get('entry_guest_name');
$data['entry_guest_message'] = $this->language->get('entry_guest_message');
$data['entry_submit'] = $this->language->get('entry_submit');
if (isset($this->error['guest_name'])) {
$data['error_guest_name'] = $this->error['guest_name'];
} else {
$data['error_guest_name'] = '';
}
if (isset($this->error['guest_message'])) {
$data['error_guest_message'] = $this->error['guest_message'];
} else {
$data['error_guest_message'] = '';
}
$data['action'] = $this->url->link('guestbook/entry', '', true);
if (isset($this->request->post['guest_name'])) {
$data['guest_name'] = $this->request->post['guest_name'];
} else {
$data['guest_name'] = '';
}
if (isset($this->request->post['guest_message'])) {
$data['guest_message'] = $this->request->post['guest_message'];
} else {
$data['guest_message'] = '';
}
$data['column_left'] = $this->load->controller('common/column_left');
$data['column_right'] = $this->load->controller('common/column_right');
$data['content_top'] = $this->load->controller('common/content_top');
$data['content_bottom'] = $this->load->controller('common/content_bottom');
$data['footer'] = $this->load->controller('common/footer');
$data['header'] = $this->load->controller('common/header');
$this->response->setOutput($this->load->view('guestbook/entry', $data));
}
protected function validate() {
if (utf8_strlen(trim($this->request->post['guest_name'])) < 1) {
$this->error['guest_name'] = $this->language->get('error_guest_name');
}
if (utf8_strlen(trim($this->request->post['guest_message'])) < 1) {
$this->error['guest_message'] = $this->language->get('error_guest_message');
}
return !$this->error;
}
}
<?php
class ControllerGuestbookEntry extends Controller {
private $error = array();
public function index() {
$this->load->language('guestbook/guestbook');
$this->document->setTitle($this->language->get('heading_title'));
if (($this->request->server['REQUEST_METHOD'] == 'POST') && $this->validate()) {
$this->load->model('guestbook/guestbook');
$data['subject'] = sprintf('New guestbook entry submitted by %s', $this->request->post['guest_name']);
$data['message'] = $this->request->post['guest_message'];
$this->model_guestbook_guestbook->processGuestbookEntry($data);
$this->session->data['success'] = $this->language->get('text_success');
$this->response->redirect($this->url->link('guestbook/entry', '', true));
}
$data['success'] = '';
if (isset($this->session->data['success'])) {
$data['success'] = $this->session->data['success'];
unset($this->session->data['success']);
}
$data['breadcrumbs'] = array();
$data['breadcrumbs'][] = array(
'text' => $this->language->get('text_home'),
'href' => $this->url->link('common/home')
);
$data['breadcrumbs'][] = array(
'text' => $this->language->get('heading_title'),
'href' => $this->url->link('guestbook/entry', '', true)
);
$data['heading_title'] = $this->language->get('heading_title');
$data['entry_guest_name'] = $this->language->get('entry_guest_name');
$data['entry_guest_message'] = $this->language->get('entry_guest_message');
$data['entry_submit'] = $this->language->get('entry_submit');
if (isset($this->error['guest_name'])) {
$data['error_guest_name'] = $this->error['guest_name'];
} else {
$data['error_guest_name'] = '';
}
if (isset($this->error['guest_message'])) {
$data['error_guest_message'] = $this->error['guest_message'];
} else {
$data['error_guest_message'] = '';
}
$data['action'] = $this->url->link('guestbook/entry', '', true);
if (isset($this->request->post['guest_name'])) {
$data['guest_name'] = $this->request->post['guest_name'];
} else {
$data['guest_name'] = '';
}
if (isset($this->request->post['guest_message'])) {
$data['guest_message'] = $this->request->post['guest_message'];
} else {
$data['guest_message'] = '';
}
$data['column_left'] = $this->load->controller('common/column_left');
$data['column_right'] = $this->load->controller('common/column_right');
$data['content_top'] = $this->load->controller('common/content_top');
$data['content_bottom'] = $this->load->controller('common/content_bottom');
$data['footer'] = $this->load->controller('common/footer');
$data['header'] = $this->load->controller('common/header');
$this->response->setOutput($this->load->view('guestbook/entry', $data));
}
protected function validate() {
if (utf8_strlen(trim($this->request->post['guest_name'])) < 1) {
$this->error['guest_name'] = $this->language->get('error_guest_name');
}
if (utf8_strlen(trim($this->request->post['guest_message'])) < 1) {
$this->error['guest_message'] = $this->language->get('error_guest_message');
}
return !$this->error;
}
}
Согласно соглашениям OpenCart об именах, имя класса начинается с ключевого слова Controller, за которым следует имя каталога Guestbook в нашем случае, в котором находится файл класса. Кроме того, в конце добавляется имя файла класса Entry.
Каждый класс контроллера предоставляет де-факто index метод, который обрабатывает большую часть логики контроллера. Далее мы рассмотрим код в index методе, и при необходимости создадим другие файлы.
В большинстве случаев мы начнем с включения языкового файла для конкретной группы. Таким образом OpenCart управляет ярлыками статического языка во всем приложении. Естественно, это делает реализацию многоязычных сайтов очень простой.
$this->load->language('guestbook/guestbook');
1
$this->load->language('guestbook/guestbook');
Прежде чем двигаться дальше, давайте создадим соответствующий языковой файл, чтобы наш контроллер мог его найти. Создайте catalog/language/en-gb/guestbook/guestbook.php файл со следующим содержимым.
<?php
// Heading
$_['heading_title'] = 'Guestbook';
// Entry
$_['entry_guest_name'] = 'Your Name';
$_['entry_guest_message'] = 'Message';
$_['entry_submit'] = 'Submit';
$_['text_success'] = 'Success: Your entry has been successfully submitted.';
// Error
$_['error_guest_name'] = 'Please enter Your Name!';
$_['error_guest_message'] = 'Please enter Message!';
<?php
// Heading
$_['heading_title'] = 'Guestbook';
// Entry
$_['entry_guest_name'] = 'Your Name';
$_['entry_guest_message'] = 'Message';
$_['entry_submit'] = 'Submit';
$_['text_success'] = 'Success: Your entry has been successfully submitted.';
// Error
$_['error_guest_name'] = 'Please enter Your Name!';
$_['error_guest_message'] = 'Please enter Message!';
Как можно увидеть, мы просто назначаем метки со своими значениями в массиве языков. Вернемся к нашему контроллеру. Следующая наша задача — настроить тег заголовка HTML для страницы.
$this->document->setTitle($this->language->get('heading_title'));
1
$this->document->setTitle($this->language->get('heading_title'));
Внимательные пользователи заметили, что мы использовали языковую переменную heading_title, определенную в языковом файле, созданном минуту назад.
Чтобы понять следующий фрагмент кода, нам нужно создать файл модели. Поэтому на мгновение я отвлеку вас на создание файла модели catalog/model/guestbook/guestbook.php со следующим содержимым.
<?php
class ModelGuestbookGuestbook extends Model {
public function processGuestbookEntry($data) {
// send email notification to store admin
$mail = new Mail();
$mail->protocol = $this->config->get('config_mail_protocol');
$mail->parameter = $this->config->get('config_mail_parameter');
$mail->smtp_hostname = $this->config->get('config_mail_smtp_hostname');
$mail->smtp_username = $this->config->get('config_mail_smtp_username');
$mail->smtp_password = html_entity_decode($this->config->get('config_mail_smtp_password'), ENT_QUOTES, 'UTF-8');
$mail->smtp_port = $this->config->get('config_mail_smtp_port');
$mail->smtp_timeout = $this->config->get('config_mail_smtp_timeout');
$mail->setTo($this->config->get('config_email'));
$mail->setFrom($this->config->get('config_email'));
$mail->setSender(html_entity_decode($this->config->get('config_name'), ENT_QUOTES, 'UTF-8'));
$mail->setSubject($data['subject']);
$mail->setText($data['message']);
$mail->send();
}
}
<?php
class ModelGuestbookGuestbook extends Model {
public function processGuestbookEntry($data) {
// send email notification to store admin
$mail = new Mail();
$mail->protocol = $this->config->get('config_mail_protocol');
$mail->parameter = $this->config->get('config_mail_parameter');
$mail->smtp_hostname = $this->config->get('config_mail_smtp_hostname');
$mail->smtp_username = $this->config->get('config_mail_smtp_username');
$mail->smtp_password = html_entity_decode($this->config->get('config_mail_smtp_password'), ENT_QUOTES, 'UTF-8');
$mail->smtp_port = $this->config->get('config_mail_smtp_port');
$mail->smtp_timeout = $this->config->get('config_mail_smtp_timeout');
$mail->setTo($this->config->get('config_email'));
$mail->setFrom($this->config->get('config_email'));
$mail->setSender(html_entity_decode($this->config->get('config_name'), ENT_QUOTES, 'UTF-8'));
$mail->setSubject($data['subject']);
$mail->setText($data['message']);
$mail->send();
}
}
В OpenCart модель отвечает за обработку бизнес-логики приложения. Если вы хотите реализовать любую логику, которая включает базу данных, то это место, куда она должна входить.
Соглашение об именовании класса модели аналогично с классом контроллера. Чтобы все было проще, мы внедрили метод, processGuestbookEntry, который уведомляет администратора магазина по электронной почте, когда пользователь добавляет запись в гостевой книге. Довольно просто, да?
Вернемся к контроллеру и рассмотрим следующий фрагмент кода в очереди.
if (($this->request->server['REQUEST_METHOD'] == 'POST') && $this->validate()) {
$this->load->model('guestbook/guestbook');
$data['subject'] = sprintf('New guestbook entry submitted by %s', $this->request->post['guest_name']);
$data['message'] = $this->request->post['guest_message'];
$this->model_guestbook_guestbook->processGuestbookEntry($data);
$this->session->data['success'] = $this->language->get('text_success');
$this->response->redirect($this->url->link('guestbook/entry', '', true));
}
1
2
3
4
5
6
7
8
if (($this->request->server['REQUEST_METHOD'] == 'POST') && $this->validate()) {
$this->load->model('guestbook/guestbook');
$data['subject'] = sprintf('New guestbook entry submitted by %s', $this->request->post['guest_name']);
$data['message'] = $this->request->post['guest_message'];
$this->model_guestbook_guestbook->processGuestbookEntry($data);
$this->session->data['success'] = $this->language->get('text_success');
$this->response->redirect($this->url->link('guestbook/entry', '', true));
}
Он проверяет действительный POST запрос и выполняет базовую проверку данных, отправленных пользователем, вызывая validate метод.
Код $this->load->model(‘guestbook/guestbook’) используется для загрузки модели, которую мы определили мгновение назад. Сразу же после этого мы готовим $data массив на основе ввода пользователя и вызываем processGuestbookEntry метод, который уведомляет администратора магазина о записи в гостевой книге. Наконец, мы перенаправляем пользователя обратно на страницу записи.
Следующий фрагмент устанавливает сообщение об успешном завершении, которое будет отображаться при отправке формы.
$data['success'] = '';
if (isset($this->session->data['success'])) {
$data['success'] = $this->session->data['success'];
unset($this->session->data['success']);
}
1
2
3
4
5
$data['success'] = '';
if (isset($this->session->data['success'])) {
$data['success'] = $this->session->data['success'];
unset($this->session->data['success']);
}
Далее есть фрагмент, который используется для создания палитры ссылок для страницы.
$data['breadcrumbs'] = array();
$data['breadcrumbs'][] = array(
'text' => $this->language->get('text_home'),
'href' => $this->url->link('common/home')
);
$data['breadcrumbs'][] = array(
'text' => $this->language->get('heading_title'),
'href' => $this->url->link('guestbook/entry', '', true)
);
1
2
3
4
5
6
7
8
9
10
11
$data['breadcrumbs'] = array();
$data['breadcrumbs'][] = array(
'text' => $this->language->get('text_home'),
'href' => $this->url->link('common/home')
);
$data['breadcrumbs'][] = array(
'text' => $this->language->get('heading_title'),
'href' => $this->url->link('guestbook/entry', '', true)
);
Следующий фрагмент является важной деталью, это то, что вы будете использовать большую часть времени для передачи информации из метода контроллера в шаблон представления.
$data['heading_title'] = $this->language->get('heading_title');
$data['entry_guest_name'] = $this->language->get('entry_guest_name');
$data['entry_guest_message'] = $this->language->get('entry_guest_message');
$data['entry_submit'] = $this->language->get('entry_submit');
1
2
3
4
$data['heading_title'] = $this->language->get('heading_title');
$data['entry_guest_name'] = $this->language->get('entry_guest_name');
$data['entry_guest_message'] = $this->language->get('entry_guest_message');
$data['entry_submit'] = $this->language->get('entry_submit');
Аналогично назначению переменных OpenCart инициализирует общие элементы page-header, footer и тп, как показано в следующем фрагменте.
$data['column_left'] = $this->load->controller('common/column_left');
$data['column_right'] = $this->load->controller('common/column_right');
$data['content_top'] = $this->load->controller('common/content_top');
$data['content_bottom'] = $this->load->controller('common/content_bottom');
$data['footer'] = $this->load->controller('common/footer');
$data['header'] = $this->load->controller('common/header');
1
2
3
4
5
6
$data['column_left'] = $this->load->controller('common/column_left');
$data['column_right'] = $this->load->controller('common/column_right');
$data['content_top'] = $this->load->controller('common/content_top');
$data['content_bottom'] = $this->load->controller('common/content_bottom');
$data['footer'] = $this->load->controller('common/footer');
$data['header'] = $this->load->controller('common/header');
Наконец, он вызывает шаблон представления, чтобы отобразить фактическую страницу!
$this->response->setOutput($this->load->view('guestbook/entry', $data));
1
$this->response->setOutput($this->load->view('guestbook/entry', $data));
Мы еще не создали шаблон представления, и сейчас идеальное время для этого! Идем дальше и создаем catalog/view/theme/default/template/guestbook/entry.tpl файл со следующим содержимым.
<?php echo $header; ?>
<div class="container">
<ul class="breadcrumb">
<?php foreach ($breadcrumbs as $breadcrumb) { ?>
<li><a href="<?php echo $breadcrumb['href']; ?>"><?php echo $breadcrumb['text']; ?></a></li>
<?php } ?>
</ul>
<?php if ($success) { ?>
<div class="alert alert-success"><i class="fa fa-check-circle"></i> <?php echo $success; ?></div>
<?php } ?>
<div class="row"><?php echo $column_left; ?>
<?php if ($column_left && $column_right) { ?>
<?php $class = 'col-sm-6'; ?>
<?php } elseif ($column_left || $column_right) { ?>
<?php $class = 'col-sm-9'; ?>
<?php } else { ?>
<?php $class = 'col-sm-12'; ?>
<?php } ?>
<div id="content" class="<?php echo $class; ?>"><?php echo $content_top; ?>
<h1><?php echo $heading_title; ?></h1>
<form action="<?php echo $action; ?>" method="post" enctype="multipart/form-data" class="form-horizontal">
<div class="form-group required">
<label class="col-sm-2 control-label" for="input-guest-name"><?php echo $entry_guest_name; ?></label>
<div class="col-sm-10">
<input type="text" value="<?php echo $guest_name; ?>" name="guest_name" placeholder="<?php echo $entry_guest_name; ?>" id="input-guest-name" class="form-control" size="10" />
<?php if ($error_guest_name) { ?>
<div class="text-danger"><?php echo $error_guest_name; ?></div>
<?php } ?>
</div>
</div>
<div class="form-group required">
<label class="col-sm-2 control-label" for="input-guest-message"><?php echo $entry_guest_message; ?></label>
<div class="col-sm-10">
<textarea name="guest_message" placeholder="<?php echo $entry_guest_message; ?>" id="input-guest-message" class="form-control"><?php echo $guest_message; ?></textarea>
<?php if ($error_guest_message) { ?>
<div class="text-danger"><?php echo $error_guest_message; ?></div>
<?php } ?>
</div>
</div>
<div class="form-group required">
<label class="col-sm-2"> </label>
<div class="col-sm-10">
<input type="submit" value="<?php echo $entry_submit; ?>" class="btn btn-primary" />
</div>
</div>
</form>
<?php echo $content_bottom; ?></div>
<?php echo $column_right; ?></div>
</div>
<?php echo $footer; ?>
<?php echo $header; ?>
<div class="container">
<ul class="breadcrumb">
<?php foreach ($breadcrumbs as $breadcrumb) { ?>
<li><a href="<?php echo $breadcrumb['href']; ?>"><?php echo $breadcrumb['text']; ?></a></li>
<?php } ?>
</ul>
<?php if ($success) { ?>
<div class="alert alert-success"><i class="fa fa-check-circle"></i> <?php echo $success; ?></div>
<?php } ?>
<div class="row"><?php echo $column_left; ?>
<?php if ($column_left && $column_right) { ?>
<?php $class = 'col-sm-6'; ?>
<?php } elseif ($column_left || $column_right) { ?>
<?php $class = 'col-sm-9'; ?>
<?php } else { ?>
<?php $class = 'col-sm-12'; ?>
<?php } ?>
<div id="content" class="<?php echo $class; ?>"><?php echo $content_top; ?>
<h1><?php echo $heading_title; ?></h1>
<form action="<?php echo $action; ?>" method="post" enctype="multipart/form-data" class="form-horizontal">
<div class="form-group required">
<label class="col-sm-2 control-label" for="input-guest-name"><?php echo $entry_guest_name; ?></label>
<div class="col-sm-10">
<input type="text" value="<?php echo $guest_name; ?>" name="guest_name" placeholder="<?php echo $entry_guest_name; ?>" id="input-guest-name" class="form-control" size="10" />
<?php if ($error_guest_name) { ?>
<div class="text-danger"><?php echo $error_guest_name; ?></div>
<?php } ?>
</div>
</div>
<div class="form-group required">
<label class="col-sm-2 control-label" for="input-guest-message"><?php echo $entry_guest_message; ?></label>
<div class="col-sm-10">
<textarea name="guest_message" placeholder="<?php echo $entry_guest_message; ?>" id="input-guest-message" class="form-control"><?php echo $guest_message; ?></textarea>
<?php if ($error_guest_message) { ?>
<div class="text-danger"><?php echo $error_guest_message; ?></div>
<?php } ?>
</div>
</div>
<div class="form-group required">
<label class="col-sm-2"> </label>
<div class="col-sm-10">
<input type="submit" value="<?php echo $entry_submit; ?>" class="btn btn-primary" />
</div>
</div>
</form>
<?php echo $content_bottom; ?></div>
<?php echo $column_right; ?></div>
</div>
<?php echo $footer; ?>
Это основной файл шаблона представления, который отвечает за отображение содержимого страницы гостевой книги. В этом файле мы только что использовали переменные, которые были настроены в index методе контроллера.
Важно отметить, что отзывчивость — это то, что поставляется с новейшими версиями OpenCart, поддерживаемыми платформой Bootstrap. Помимо прочего, это довольно обычный материал HTML, который легко понять.
Итак, это то, что касается настройки файла.
У нас есть все готово, но как вы получите доступ к файлу из front-end?
Во front-end вы можете получить доступ к странице Guestbook, добавив переменную переадресации маршрута , поэтому URL-адрес должен быть похож на http: //your-opencart-store-url/index.php? Route = guestbook / entry .
Давайте разберёмся, как OpenCart сопоставляет URL-адрес с конкретным файлом контроллера. Формат переменной маршрута — {directory}/{filename}/{methodname}.
Компонент {directory} отображает в каталоге под catalog/controller.
В {filename}отображает имя файла контроллера под catalog/controller/{directory}.
Наконец, ищет метод контроллера {methodname}, если он указан в маршруте, иначе он вызовет index метод по умолчанию.
Так выглядит конечный результат.
Конечно, вы можете пойти дальше и протестировать его, отправив форму, и тогда придёт уведомление по электронной почте на адрес, зарегистрированный в качестве администратора магазина.
Вывод
В любом фреймворке всегда интересно проводить реализацию собственных пользовательских функций. Это стало предметом сегодняшнего учебника, в котором мы расширили OpenCart и разработали пользовательские контроллеры, создав довольно простую, но полезную функциональность гостевой книги.
В этом процессе мы поняли, что речь идет не только о контроллерах — было несколько других ключевых элементов, которые были неизбежны. Поэтому мы также рассмотрели их: модель, язык и представление.