HUFERSIL.WEBDEVELOPER

Criando um catálogo de produtos com Lumine e CodeIgniter – Parte 9

Olá pessoal,

Hoje veremos como realizar a pesquisa de produtos baseado na categoria que o usuário selecionou.
Como as categorias são cadastradas de forma hierárquica, iremos também consultar nas categorias filhas, netas, bisnetas, etc.

Preparando os arquivos de controller e model

Primeiramente, vamos alterar a função na classe de produtos que retorna os itens para o site, para incluirmos os filtros por palavra-chave e por categoria. Abra o arquivo application/models/Produto.php e altere a função getProdutosSite pela função abaixo:

    /**
     * Recupera uma lista de produtos.
     * 
     * Já faz o join com a categoria do produto e com
     * a imagem principal do produto. 
     * 
     * @param string $order Ordem em que os produtos deverão ser listados
     * @param int $limit Limite de produtos nesta consulta
     * @param int $offset Inicio da recuperação dos produtos
     * @return int Numero de registros encontrados
     * @param array $categorias Lista dos codigos das categorias para pesquisa
     * @param string $keyword Palavra chave para filtro
     * @return number Numero de registros encontrados
     * @author Hugo Ferreira da Silva
     */
    public function getProdutosSite($order, $limit, $offset = 0, array $categorias = array(), $keyword = ''){
    	$this->alias('p')
	    	->join(new Categoria(),'inner','c')
	    	->join(new Foto(),'inner','f',null,null,'f.ordem = 1')
	    	->select('f.thumb, f.grande')
	    	->select('p.nome,p.codproduto,p.permalink,substring(p.descricao, 1, 100) as descricao')
	    	->select('c.nome as categoria, c.permalink as permalink_categoria,p.codcategoria')
	    	->order( $order );
 
    	if(!empty($categorias)){
    		$this->where('p.codcategoria in (?)', $categorias);
    	}
 
    	if(!empty($keyword)){
    		$this->where('(p.nome like ? OR p.descricao like ?)', $keyword, $keyword);
    	}
 
    	$total = $this->count();
 
    	$this->order($order)
    		->limit($offset, $limit)
    		->find();
 
    	return $total;
    }

Para segregarmos as responsabilidades e deixar o nosso código mais limpo (por conseguinte, mais fácil de manter) vamos fazer criar uma nova controller para as operações onde a fonte de dados principal é a categoria do produto. Como neste caso, iremos pesquisar os produtos por categoria, criaremos uma controller chamada “categorias”, no caminho application/controllers/categorias.php, com o seguinte conteúdo:

<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
 
/**
 * Controller para operações relacionadas as categorias na parte publica
 * 
 *
 * @author Hugo Ferreira da Silva
 *
 */
class Categorias extends SiteController {
 
	/**
	 * Exibe os itens de uma determinada categoria.
	 * 
	 * <p>também varremos as categorias filhas e netas
	 * para uma listagem completa dos produtos.</p>
	 * 
	 * @param string $permalink
	 * @author Hugo Ferreira da Silva
	 * @return void
	 */
	public function listar($permalink, $pagina = 0){
		list($codigo) = explode('-', $permalink);
 
		$dao        = new Categoria();
		$categorias = $dao->getDescendentes($codigo);
 
		$stack   = $categorias;
		$codigos = array();
 
		while(!empty($stack)){
			$item = array_shift($stack);
			$codigos[] = $item['codcategoria'];
 
			if(!empty($item['categorias'])){
				$stack = array_merge($stack, $item['categorias']);
			}
		}
 
		// offset de pesquisa
		$offset = max(0, $pagina - 1) * LIMITE_PAGINACAO_PRODUTOS;
 
		// pegando os produtos das categorias
		$lista = new Produto();
		$total = $lista->getProdutosSite('p.nome asc', LIMITE_PAGINACAO_PRODUTOS, $offset, $codigos);
 
		$this->assign('total', $total);
		$this->assign('produtos', $lista->allToArray(false,true));
		$this->assign('breadcrumb', $dao->getArvore($codigo));
 
		// carrega a biblioteca de paginação
		$this->load->library('pagination');
		$this->loadCommonAssets();
		$this->display('categorias/listar');
	}
 
}

Como dito no início, nossas categorias podem ser cadastradas de forma hierárquica. Logo, se o usuário clicar em uma categoria principal, ele deverá também visualizar os produtos que se encontram nas categorias descendentes. Para isto, note que chamamos um método novo da classe Categoria, getDescendentes. Este método recupera todas as categorias que são descendentes da categoria informada, incluindo também no retorno do método a categoria informada como parâmetro. Desta forma, podemos utilizar os resultados de forma fácil para encontrar os produtos relacionados a elas. Também para melhorar a performance, fazemos de forma iterativa sem recursividade, utilizando o conceito de fila, ou seja, verificamos se existem itens dentro de uma fila a serem pesquisados. Enquanto houverem elementos, efetuamos as pesquisas de categorias filhas, netas, bisnetas, etc. Coloque os códigos abaixo no arquivo application/model/Categoria.php:

    /**
     * Recupera as categorias descendentes (filhas, netas, bisnetas, etc) da categoria informada
     * 
     * @param int $codigo Codigo da categoria desejada
     * @author Hugo Ferreira da Silva
     * @return array Lista contendo os dados das categorias descendentes
     */
    public function getDescendentes($codigo){
    	$lista = array($codigo);
    	$result = array();
 
    	$categoria = new Categoria();
    	$categoria->get($codigo);
 
    	$obj = $categoria->toArray();
    	$obj['codpai'] = null;
    	$result[] = $obj;
 
    	$categoria->reset();
 
    	while(!empty($lista)){
    		$categoria->alias('c')
    			->where('c.codpai IN (?)', $lista)
    			->find();
 
    		$lista = array();
 
    		while($categoria->fetch()){
    			$lista[] = $categoria->codcategoria;
    			$result[] = $categoria->toArray();
    		}
 
    		$categoria->reset();
    	}
 
    	return fncAninharElementos($result, 'codcategoria','codpai','categorias');
    }

Também é necessária uma paginação de resultados, pois do contrário, a lista de produtos pode ser muito grande, ficando inviável sua exibição na tela. Note que utilizamos uma constante para indicar o numero de resultados por página. Abra o arquivo application/config/constants.php e adicione a linha abaixo:

define('LIMITE_PAGINACAO_PRODUTOS', 4);

Definições da View

Agora, vamos criar os arquivos de visualização.
Como visto no inicio destes artigos, estamos separando as views de conformidade com suas respectivas controllers, assim temos uma visão melhor de como os arquivos estão dispostos. Como o nome de nossa controller é categorias e o nome do método que chamamos é listar, criamos a controller abaixo dentro do endereço appication/views/site/categorias/listar.php com o conteúdo abaixo:

<div class="top-search clearfix">
	<h3 class="head-pet">
		<span>Pesquisa de Produtos</span>
	</h3>
	<form action="#" id="searchform" method="post">
		<p>
			<input type="text" name="2" id="s" class="field"
				value="Pesquisar Por" onfocus="this.value=''" /> <input
				type="submit" name="s_submit" id="s-submit" value="" />
		</p>
	</form>
	<p class="statement">
		<ul class="breadcrumb">
			<li>Você está em:</li>
			<?php 
			echo fncImprimeConteudoAninhado(
				$breadcrumb
				, '<li><a href="'.site_url('categorias/lista/:codcategoria-:nome').'">:nome</a></li>'
				, ''
			);
			?>
		</ul>
	</p>
</div>
 
<div id="content">
	<div id="whats-hot">
		<h2 class="w-bot-border">
			Produtos <span>Encontrados</span>
		</h2>
 
		<?php if(!empty($produtos)): ?>
		<ul class="cat-list clearfix">
			<?php 
				$linkProduto = site_url('produtos/detalhes/:codproduto-:permalink');
				$linkCategoria = site_url('categorias/listar/:codcategoria-:permalink_categoria');
				$tpl =  '<li>
				                    	<h3><a href="'.$linkProduto.'">:nome</a></h3>
				                        <a href="'.$linkProduto.'" class="img-box"><img src="'.base_url(':grande').'" alt=":nome" /></a>
				                        <h4><a href="'.$linkCategoria.'">:categoria</a></h4>
				                        <p>:descricao<a href="#">... mais</a></p>
			                    </li>';
				echo fncImprimeConteudoAninhado($produtos, $tpl, 'idx');
 
				// configurações da paginacao
				// @link http://codeigniter.com/user_guide/libraries/pagination.html
				$config['uri_segment'] = 4;
				$config['total_rows'] = $total;
				$config['per_page'] = LIMITE_PAGINACAO_PRODUTOS;
				$config['base_url'] = site_url('categorias/listar/' . $this->uri->segment(3));
				$config['use_page_numbers'] = TRUE;
				$this->pagination->initialize($config);
			?>
		</ul>
		<?php 
			if($total > LIMITE_PAGINACAO_PRODUTOS):
				// exibe a paginacao
				printf('<div class="paginacao clearfix"> Páginas: %s </div>', $this->pagination->create_links());
			endif;
 
		else:
			echo '<div>Nenhum produto encontrado</div>';
		endif;
		?>
	</div>
</div>

Se tudo estiver correto, o resultado deverá ser semelhante a este.

Na próxima iremos fazer o formulário de contato.

@braços e fiquem com Deus!

Deixar uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *

*

Pode usar estas etiquetas HTML e atributos: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="" highlight="">