Portuguese (Português) translation by Anderson (you can also view the original English article)
Como um desenvolvedor, é sempre interessante criar materiais personalizados em qualquer estruturas, assim é para os plug-ins OpenCart também.
Nesta série de duas partes, vou explicar como desenvolver plugins personalizados no OpenCart. Do ponto de vista de um desenvolvedor iniciante, vamos passar os detalhes de desenvolvimento de extensão no OpenCart. Também criaremos um plugin personalizado pequeno para demonstrar cada aspecto da estrutura do plugin OpenCart.
Nesta primeira parte, criaremos um plug-in personalizado que ira exibir produtos novos na frente de sua loja e você poderá configurar o número de produtos no próprio painel administrativo. Este é o objetivo deste artigo que é desenvolver um plug-in de back-end com um formulário de configuração.
Eu suponho que você configurou a versão mais recente do OpenCart, que é 2.1.0.2 como de escrever isso. Antes de prosseguir e desenvolver um plugin real, eu vou orientá-lo através da arquitetura básica do OpenCart na próxima seção.
MVCL em poucas palavras
O OpenCart é desenvolvido com um dos mais populares padrões de desenvolvimento web, o padrão MVC, com uma pequena variação, ou melhor, eu diria que é uma adição. A adição é na forma de um componente de linguagem que torna MVCL no mundo do OpenCart. Pode ser que você já tenha ouvido falar deste padrão, mas para quem é iniciante, vou rapidamente resumir o que é este padrão.
O M em MVC significa modelo, e é aí que reside a maior parte da lógica desse negócio. No contexto do OpenCart, é o modelo que interage com a camada de abstração de banco de dados para fazer todo o trabalho pesado necessário para executar o armazenamento. É uma área onde você vai encontrar-se na maioria das vezes como um desenvolvedor.
Em seguida, o V significa Ver, e representa a camada de apresentação do aplicativo. Como o nome sugere, ele só lida com a lógica de apresentação de qualquer página, e recebe a entrada de outras camadas e gera a saída HTML na maioria das vezes. A lógica dessa aplicação deve ser mantida afastada dessa camada; Ele só deve se preocupar com o que fazer em vez de como fazê-lo.
É o C, o controlador, no MVC que se senta na frente de tudo, lidar com cada pedido e tratá-lo em conformidade É uma área que inclui a maior parte da lógica do aplicativo, desde manipulação e validação de entrada do usuário até o carregamento do modelo adequado e visualização de componentes para preparar a saída da página.
Finalmente, há um componente adicional, L, que significa linguagem Faz com que a criação de sites multilíngue seja bem mais facil.
Essa é uma visão rápida da arquitetura do OpenCart, e isso fará mais sentido à medida que avançarmos para a explicação detalhada de cada componente.
O esqueleto de um plugin OpenCart
Vamos dar uma rápida olhada na lista de arquivos que precisamos implementar o plug-in de back-end personalizado.
-
admin/english/portuguese-br/module/recent_products.php:
É um arquivo que contém etiquetas estáticas usadas em toda a aplicação do administrador. -
admin/controller/module/recent_products.php:
É um arquivo de controlador que contém toda lógica de aplicação do nosso módulo. -
admin/view/template/module/recent_products.tpl:
É um arquivo de modelo de visualização e contém código XHTML.
Na próxima seção, vamos criar cada arquivo mencionado acima, com uma explicação em profundidade.
De acordo com as convenções, precisamos colocar os arquivos de plug-ins personalizados no diretório do módulo. Neste caso, como estamos desenvolvendo um plugin de backend, serão os diretórios sob admin que mantêm nossos arquivos. É claro que os arquivos estão espalhados em diretórios diferentes, ou melhor, componentes, de acordo com a arquitetura OpenCart mostrada acima.
Criar arquivos para o plug-in de back-end
Nesta seção, começaremos a criar os arquivos do módulo. Primeiro, criaremos um arquivo de idiomaadmin/language/english/module/recent_products.php
Com o seguinte conteúdo É um arquivo importante do ponto de vista do OpenCart, pois é uma obrigação para seu plugin ser detectado pelo OpenCart.
1 |
<?php
|
2 |
// admin/language/english/module/recent_products.php
|
3 |
// Heading
|
4 |
$_['heading_title'] = 'Recent Products'; |
5 |
|
6 |
// Text
|
7 |
$_['text_module'] = 'Modules'; |
8 |
$_['text_success'] = 'Success: You have modified Recent Products module!'; |
9 |
$_['text_edit'] = 'Edit Recent Products Module'; |
10 |
|
11 |
// Entry
|
12 |
$_['entry_name'] = 'Module Name'; |
13 |
$_['entry_limit'] = 'Limit'; |
14 |
$_['entry_status'] = 'Status'; |
15 |
|
16 |
// Error
|
17 |
$_['error_permission'] = 'Warning: You do not have permission to modify Recent Products module!'; |
18 |
$_['error_name'] = 'Module Name must be between 3 and 64 characters!'; |
Como você pode ver, estamos atribuindo rótulos estáticos a um array PHP. Mais adiante, você terá acesso a essas variáveis no arquivo de modelo de visualização conforme a matriz é convertida em variáveis PHP.
Você também pode ter notado que o arquivo é criado sob o diretório em english, pois é o idioma padrão da loja. Naturalmente, no caso de um site multilíngue, você precisará certificar-se de que você criá-lo para outros idiomas também. Por exemplo, a versão portugues do mesmo arquivo deve ser criada em:admin/language/portuguese-br/module/recent_products.php
Em seguida, criaremos um dos arquivos de plug-ins mais importantes: o arquivo do controlador. Vamos em frente e criaradmin/controller/module/recent_products.php
Com o seguinte conteúdo.
1 |
<?php
|
2 |
// admin/controller/module/recent_products.php
|
3 |
class ControllerModuleRecentProducts extends Controller { |
4 |
private $error = array(); |
5 |
|
6 |
public function index() { |
7 |
$this->load->language('module/recent_products'); |
8 |
|
9 |
$this->document->setTitle($this->language->get('heading_title')); |
10 |
|
11 |
$this->load->model('extension/module'); |
12 |
|
13 |
if (($this->request->server['REQUEST_METHOD'] == 'POST') && $this->validate()) { |
14 |
if (!isset($this->request->get['module_id'])) { |
15 |
$this->model_extension_module->addModule('recent_products', $this->request->post); |
16 |
} else { |
17 |
$this->model_extension_module->editModule($this->request->get['module_id'], $this->request->post); |
18 |
}
|
19 |
|
20 |
$this->session->data['success'] = $this->language->get('text_success'); |
21 |
|
22 |
$this->response->redirect($this->url->link('extension/module', 'token=' . $this->session->data['token'], 'SSL')); |
23 |
}
|
24 |
|
25 |
$data['heading_title'] = $this->language->get('heading_title'); |
26 |
|
27 |
$data['text_edit'] = $this->language->get('text_edit'); |
28 |
$data['text_enabled'] = $this->language->get('text_enabled'); |
29 |
$data['text_disabled'] = $this->language->get('text_disabled'); |
30 |
|
31 |
$data['entry_name'] = $this->language->get('entry_name'); |
32 |
$data['entry_limit'] = $this->language->get('entry_limit'); |
33 |
$data['entry_status'] = $this->language->get('entry_status'); |
34 |
|
35 |
$data['button_save'] = $this->language->get('button_save'); |
36 |
$data['button_cancel'] = $this->language->get('button_cancel'); |
37 |
|
38 |
if (isset($this->error['warning'])) { |
39 |
$data['error_warning'] = $this->error['warning']; |
40 |
} else { |
41 |
$data['error_warning'] = ''; |
42 |
}
|
43 |
|
44 |
if (isset($this->error['name'])) { |
45 |
$data['error_name'] = $this->error['name']; |
46 |
} else { |
47 |
$data['error_name'] = ''; |
48 |
}
|
49 |
|
50 |
$data['breadcrumbs'] = array(); |
51 |
|
52 |
$data['breadcrumbs'][] = array( |
53 |
'text' => $this->language->get('text_home'), |
54 |
'href' => $this->url->link('common/dashboard', 'token=' . $this->session->data['token'], 'SSL') |
55 |
);
|
56 |
|
57 |
$data['breadcrumbs'][] = array( |
58 |
'text' => $this->language->get('text_module'), |
59 |
'href' => $this->url->link('extension/module', 'token=' . $this->session->data['token'], 'SSL') |
60 |
);
|
61 |
|
62 |
if (!isset($this->request->get['module_id'])) { |
63 |
$data['breadcrumbs'][] = array( |
64 |
'text' => $this->language->get('heading_title'), |
65 |
'href' => $this->url->link('module/recent_products', 'token=' . $this->session->data['token'], 'SSL') |
66 |
);
|
67 |
} else { |
68 |
$data['breadcrumbs'][] = array( |
69 |
'text' => $this->language->get('heading_title'), |
70 |
'href' => $this->url->link('module/recent_products', 'token=' . $this->session->data['token'] . '&module_id=' . $this->request->get['module_id'], 'SSL') |
71 |
);
|
72 |
}
|
73 |
|
74 |
if (!isset($this->request->get['module_id'])) { |
75 |
$data['action'] = $this->url->link('module/recent_products', 'token=' . $this->session->data['token'], 'SSL'); |
76 |
} else { |
77 |
$data['action'] = $this->url->link('module/recent_products', 'token=' . $this->session->data['token'] . '&module_id=' . $this->request->get['module_id'], 'SSL'); |
78 |
}
|
79 |
|
80 |
$data['cancel'] = $this->url->link('extension/module', 'token=' . $this->session->data['token'], 'SSL'); |
81 |
|
82 |
if (isset($this->request->get['module_id']) && ($this->request->server['REQUEST_METHOD'] != 'POST')) { |
83 |
$module_info = $this->model_extension_module->getModule($this->request->get['module_id']); |
84 |
}
|
85 |
|
86 |
if (isset($this->request->post['name'])) { |
87 |
$data['name'] = $this->request->post['name']; |
88 |
} elseif (!empty($module_info)) { |
89 |
$data['name'] = $module_info['name']; |
90 |
} else { |
91 |
$data['name'] = ''; |
92 |
}
|
93 |
|
94 |
if (isset($this->request->post['limit'])) { |
95 |
$data['limit'] = $this->request->post['limit']; |
96 |
} elseif (!empty($module_info)) { |
97 |
$data['limit'] = $module_info['limit']; |
98 |
} else { |
99 |
$data['limit'] = 5; |
100 |
}
|
101 |
|
102 |
if (isset($this->request->post['status'])) { |
103 |
$data['status'] = $this->request->post['status']; |
104 |
} elseif (!empty($module_info)) { |
105 |
$data['status'] = $module_info['status']; |
106 |
} else { |
107 |
$data['status'] = ''; |
108 |
}
|
109 |
|
110 |
$data['header'] = $this->load->controller('common/header'); |
111 |
$data['column_left'] = $this->load->controller('common/column_left'); |
112 |
$data['footer'] = $this->load->controller('common/footer'); |
113 |
|
114 |
$this->response->setOutput($this->load->view('module/recent_products.tpl', $data)); |
115 |
}
|
116 |
|
117 |
protected function validate() { |
118 |
if (!$this->user->hasPermission('modify', 'module/recent_products')) { |
119 |
$this->error['warning'] = $this->language->get('error_permission'); |
120 |
}
|
121 |
|
122 |
if ((utf8_strlen($this->request->post['name']) < 3) || (utf8_strlen($this->request->post['name']) > 64)) { |
123 |
$this->error['name'] = $this->language->get('error_name'); |
124 |
}
|
125 |
|
126 |
return !$this->error; |
127 |
}
|
128 |
}
|
Ele define a nova classe para o nosso plugin personalizado que estende a classe de Controller
base. Conforme as convenções, o nome da classe deve imitar a estrutura de diretório sob a qual o arquivo é colocado. Assim, o caminho controller/module/recent_products.phpÉ convertido para ControllerModuleRecentProducts
substituindo a barra e caracteres sublinhado de acordo!
Em seguida, há um método index
de fato que é chamado quando o plugin é carregado no front-end. Portanto, é um método de index que define a maior parte da lógica da aplicação do plug-in.
No contexto do presente pedido, a abreviatura$this->load->language
Carrega o arquivo de idioma correspondente. No nosso caso, ele carrega o arquivo de idioma definido na seção anterior. A sintaxe é bastante simples - você só precisa passar o nome do plugin prefixado por module/
As variáveis de idioma podem ser acessadas$this->language->get
Pelo método
Em seguida, define o título da página usando o método setTitle
do objeto de documento.
Avançando, o modelo $this->load->model
é usado para carregar o modelo do módulo. É a classe do modelo que fornece métodos de utilidade para salvar os parâmetros do módulo e similares.
Em seguida, há um trecho importante como mostrado abaixo que verifica se é POST envio de dados e salva a configuração do módulo nesse caso.
1 |
if (($this->request->server['REQUEST_METHOD'] == 'POST') && $this->validate()) { |
2 |
if (!isset($this->request->get['module_id'])) { |
3 |
$this->model_extension_module->addModule('recent_products', $this->request->post); |
4 |
} else { |
5 |
$this->model_extension_module->editModule($this->request->get['module_id'], $this->request->post); |
6 |
}
|
7 |
|
8 |
$this->session->data['success'] = $this->language->get('text_success'); |
9 |
$this->response->redirect($this->url->link('extension/module', 'token=' . $this->session->data['token'], 'SSL')); |
10 |
}
|
Além disso, estamos atribuindo rótulos de idioma como heading_title
e text_edit
à matriz de $data
para que possamos usá-los no arquivo de modelo de visualização
Em seguida, há um snippet que constrói os links de breadcrumb corretos para a página de configuração.
1 |
$data['breadcrumbs'] = array(); |
2 |
|
3 |
$data['breadcrumbs'][] = array( |
4 |
'text' => $this->language->get('text_home'), |
5 |
'href' => $this->url->link('common/dashboard', 'token=' . $this->session->data['token'], 'SSL') |
6 |
);
|
7 |
|
8 |
$data['breadcrumbs'][] = array( |
9 |
'text' => $this->language->get('text_module'), |
10 |
'href' => $this->url->link('extension/module', 'token=' . $this->session->data['token'], 'SSL') |
11 |
);
|
12 |
|
13 |
if (!isset($this->request->get['module_id'])) { |
14 |
$data['breadcrumbs'][] = array( |
15 |
'text' => $this->language->get('heading_title'), |
16 |
'href' => $this->url->link('module/recent_products', 'token=' . $this->session->data['token'], 'SSL') |
17 |
);
|
18 |
} else { |
19 |
$data['breadcrumbs'][] = array( |
20 |
'text' => $this->language->get('heading_title'), |
21 |
'href' => $this->url->link('module/recent_products', 'token=' . $this->session->data['token'] . '&module_id=' . $this->request->get['module_id'], 'SSL') |
22 |
);
|
23 |
}
|
Se o módulo já tivesse sido configurado anteriormente e no modo de edição, o snippet a seguir preencherá a configuração de módulo padrão.
1 |
if (isset($this->request->get['module_id']) && ($this->request->server['REQUEST_METHOD'] != 'POST')) { |
2 |
$module_info = $this->model_extension_module->getModule($this->request->get['module_id']); |
3 |
}
|
Finalmente, estamos carregando os elementos de página comuns como cabeçalho, rodapé e barra lateral esquerda. Exibe o arquivo recent_products.tpl
e exibe o formulário de configuração
Há algumas notas importantes a serem lembradas no arquivo do controlador. Você verá muitas chamadas como $this-> load-> ELEMENT
, onde ELEMENT
pode ser view, model ou language. Ele carrega os componentes de view, model e language correspondentes
O próximo e último arquivo para o artigo de hoje é um arquivo de template view admin/view/template/module/recent_products.tpl
Vá em frente e criá-lo!
1 |
<!-- admin/view/template/module/recent_products.tpl -->
|
2 |
<?php echo $header; ?><?php echo $column_left; ?> |
3 |
<div id="content"> |
4 |
<div class="page-header"> |
5 |
<div class="container-fluid"> |
6 |
<div class="pull-right"> |
7 |
<button type="submit" form="form-recent-products" data-toggle="tooltip" title="<?php echo $button_save; ?>" class="btn btn-primary"><i class="fa fa-save"></i></button> |
8 |
<a href="<?php echo $cancel; ?>" data-toggle="tooltip" title="<?php echo $button_cancel; ?>" class="btn btn-default"><i class="fa fa-reply"></i></a></div> |
9 |
<h1><?php echo $heading_title; ?></h1> |
10 |
<ul class="breadcrumb"> |
11 |
<?php foreach ($breadcrumbs as $breadcrumb) { ?> |
12 |
<li><a href="<?php echo $breadcrumb['href']; ?>"><?php echo $breadcrumb['text']; ?></a></li> |
13 |
<?php } ?> |
14 |
</ul>
|
15 |
</div>
|
16 |
</div>
|
17 |
<div class="container-fluid"> |
18 |
<?php if ($error_warning) { ?> |
19 |
<div class="alert alert-danger"><i class="fa fa-exclamation-circle"></i> <?php echo $error_warning; ?> |
20 |
<button type="button" class="close" data-dismiss="alert">×</button> |
21 |
</div>
|
22 |
<?php } ?> |
23 |
<div class="panel panel-default"> |
24 |
<div class="panel-heading"> |
25 |
<h3 class="panel-title"><i class="fa fa-pencil"></i> <?php echo $text_edit; ?></h3> |
26 |
</div>
|
27 |
<div class="panel-body"> |
28 |
<form action="<?php echo $action; ?>" method="post" enctype="multipart/form-data" id="form-recent-products" class="form-horizontal"> |
29 |
<div class="form-group"> |
30 |
<label class="col-sm-2 control-label" for="input-name"><?php echo $entry_name; ?></label> |
31 |
<div class="col-sm-10"> |
32 |
<input type="text" name="name" value="<?php echo $name; ?>" placeholder="<?php echo $entry_name; ?>" id="input-name" class="form-control" /> |
33 |
<?php if ($error_name) { ?> |
34 |
<div class="text-danger"><?php echo $error_name; ?></div> |
35 |
<?php } ?> |
36 |
</div>
|
37 |
</div>
|
38 |
<div class="form-group"> |
39 |
<label class="col-sm-2 control-label" for="input-limit"><?php echo $entry_limit; ?></label> |
40 |
<div class="col-sm-10"> |
41 |
<input type="text" name="limit" value="<?php echo $limit; ?>" placeholder="<?php echo $entry_limit; ?>" id="input-limit" class="form-control" /> |
42 |
</div>
|
43 |
</div>
|
44 |
<div class="form-group"> |
45 |
<label class="col-sm-2 control-label" for="input-status"><?php echo $entry_status; ?></label> |
46 |
<div class="col-sm-10"> |
47 |
<select name="status" id="input-status" class="form-control"> |
48 |
<?php if ($status) { ?> |
49 |
<option value="1" selected="selected"><?php echo $text_enabled; ?></option> |
50 |
<option value="0"><?php echo $text_disabled; ?></option> |
51 |
<?php } else { ?> |
52 |
<option value="1"><?php echo $text_enabled; ?></option> |
53 |
<option value="0" selected="selected"><?php echo $text_disabled; ?></option> |
54 |
<?php } ?> |
55 |
</select>
|
56 |
</div>
|
57 |
</div>
|
58 |
</form>
|
59 |
</div>
|
60 |
</div>
|
61 |
</div>
|
62 |
</div>
|
63 |
<?php echo $footer; ?> |
Usuários com olhos afiados já terão notado que ele está apenas exibindo as variáveis que foram passadas do arquivo do controlador. Além disso, é simples código XHTML para exibir o formulário de configuração, é a cereja no topo do bolo.
Então, é isso, tanto quanto a configuração do arquivo está em causa para o nosso plug-in personalizado back-end.
Ativar o Plugin
Vá até o back-end do OpenCart e navegue até Extensões> Módulos. Você deve ver Produtos recentes na lista de modulos. Clique no sinal + para instalar o módulo, conforme mostrado na seguinte captura de tela.



Uma vez instalado, você verá um ícone de edição. Clique nesse botão para abrir o formulário de configuração do módulo.



No formulário de configuração, você pode definir o número de produtos recentes que deseja exibir no bloco front-end. Além disso, não se esqueça de definir o campo de status como Habilitado! Salve o módulo, e ele deve ser algo parecido com isto.



Há uma nova entrada para o módulo intitulado Produtos recentes> My Recent Block Plugin. A razão é que você pode replicá-lo várias vezes para páginas diferentes!
Então, estamos quase terminando! Fizemos um plugin personalizado de back-end completo no OpenCart. Na próxima parte, iremos passar pela parte frontal do mesmo que exibe um bloco de produtos bonitos no front-end!
Conclusão
Hoje, discutimos o desenvolvimento de plug-ins personalizados no OpenCart. Na primeira parte desta série de duas partes, passamos pelo desenvolvimento de plug-ins de back-end e criamos um plugin personalizado de trabalho que fornece um formulário de configuração.
Se você está procurando ferramentas OpenCart adicionais, utilitários, extensões e assim por diante que você pode aproveitar em seus próprios projetos ou para sua própria educação, ver o que temos disponíveis no mercado.
Na próxima parte, completaremos o plug-in criando a parte front-end que exibe as listagens de produtos no front-end. Para quaisquer dúvidas e comentários, use o feed de comentários abaixo.