микрозаймы онлайн займы на карту займы по паспорту

CRUD Laravel + ExtJS 10

Ola Pessoal

Criei esse CRUD usando Laravel e ExtJS para ajudar o pessoal que quer aprender ExtJS e também o pessoal do ExtJS a aprender um pouco de Laravel.

O foco desse tutorial não é explicar do zero como o ExtJS funciona, para quem não tem conhecimento recomendo o curso gratuito feito pela Loianehttp://www.loiane.com/2011/11/curso-de-extjs-4-gratuito/ e http://www.extjs.com.br/forum

A minha intenção é dar uma direção para quem quer começar a utilizar ExtJS com Laravel, eu procurei utilizar vários tipos de campo para poder explicar alguns recursos interessantes do ExtJS

nesse exemplo inclui os seguintes recursos:

  • ExtJS no padrão MVC
  • Grid para listar os funcionários com paginação
  • Toolbar com botões: Criar, Editar, Excluir e Limpar Filtros de pesquisa
  • Campo CPF com validação e mascara
  • Tratamento de string com formatação de maiúscula e minuscula no campo NOME
  • Campos data no padrão Y-m-d mas formatados para BR
  • Combobox multiSelect com checkbox e edição em linha do grid
  • Campo tipo monetário com mascara para moeda Real R$
  • Edição na linha do grid dando 2 cliques ou selecionando a linha e editando em uma janela
  • Somatória(summary) de salários no final do grid
  • Pesquisa de campos com vários modos diferentes (observar imagem abaixo)
  • Coluna(actioncolumn ) botão de ação no grid
  • Janela de notificação com mensagens personalizadas e fechamento automático

tabela de exemplo:

DROP TABLE IF EXISTS funcionarios;
CREATE TABLE funcionarios (
	id SMALLINT ( 5 ) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
	nome VARCHAR ( 40 ) NOT NULL,
	data_nascimento DATE,
	cpf CHAR ( 11 ) UNIQUE,
	sexo ENUM ( 'M', 'F' ),
	salario DECIMAL ( 10,2 ),
	beneficio SET ( 'VT', 'CM', 'CO' ),
	ativo ENUM ( '0', '1', '2' ) COMMENT '0=Demitido|1=Ativo|2=Afastado/Ferias'
) ENGINE = innodb CHARACTER SET utf8 COLLATE utf8_general_ci;

o script começa com app.js:

Ext.Loader.setConfig({
	enabled         : true
	,disableCaching : true
	,paths          : {
		'Ext.ux' : '/laravel_extjs/public/extjs/ux'
	}
});

Ext.application({
    name         : 'LaraExt'
	,appFolder   : '/laravel_extjs/public/app'
    ,controllers : [
		'Funcionario'
	]
    ,autoCreateViewport : true
});

ele ira procurar o controller com o nome “funcionario”

Controller ExtJS (Funcionario.js):

Ext.define('LaraExt.controller.Funcionario', {
    extend    : 'Ext.app.Controller'
    ,requires : [
        'Ext.ux.window.Notification'
        ,'Ext.ux.TextMaskPlugin'
        ,'Ext.ux.grid.FiltersFeature'
    ]
    ,refs     : [{ref: 'funcionariogrid', xtype: 'funcionariogrid' }]
    ,stores   : ['Funcionario']
    ,models   : ['Funcionario']
    ,views    : [
        'funcionario.Form'
        ,'funcionario.Combo'
        ,'funcionario.Grid'
        ,'funcionario.Window'
    ]

    ,features: [
        {
            id: 'salario',
            itemId:'salario',
            ftype: 'summary',
            dock: 'bottom'
        }
    ]

    ,init: function() {
        var me = this;

        me.control({
            'funcionariogrid': {
                render           : this.funcionarioRender
                ,selectionchange : this.funcionarioSelectionChange
            }
            ,'funcionariogrid button[action=create]': {
                click: this.funcionarioBtnCreate
            }
            ,'funcionariogrid button[action=update]': {
                click: this.funcionarioBtnUpdate
            }
            ,'funcionariogrid button[action=destroy]': {
                click: this.funcionarioBtnDestroy
            }
            ,'funcionariogrid button[action=clear]': {
                click: this.funcionarioBtnClearFilters
            }
            ,'funcionariogrid actioncolumn': {
                click: this.funcionarioActionClick
            }
            ,'funcionariowindow button[action=save]': {
                click: this.funcionarioBtnSave
            }
            ,'funcionariowindow button[action=cancel]': {
                click: this.funcionarioBtnCancel
            }
        });
    }

    ,funcionarioRender: function() {
        this.getFuncionarioStore().on({
            write : this.funcionarioDeselectAll
        });

        this.getFuncionarioStore().load();
    }

    ,funcionarioDeselectAll: function() {
        var grid = Ext.ComponentQuery.query('funcionariogrid')[0];
        grid.getSelectionModel().deselectAll();
    }

    ,funcionarioSelectionChange: function(selModel, selected) {
        var grid = selModel.view.ownerCt;

        grid.down('#btnDestroy').setDisabled(!selected.length);
        grid.down('#btnUpdate').setDisabled(!(selected.length == 1));
        grid.getView().refresh();
    }

    ,funcionarioBtnCreate: function(button) {
        Ext.widget('funcionariowindow', {animateTarget:button.el});
    }

    ,funcionarioBtnUpdate: function(button) {
        var grid   = button.up('grid');
        var view   = Ext.widget('funcionariowindow', {animateTarget:button.el});
        var record = grid.getSelectionModel().getSelection()[0];
        view.down('form').loadRecord(record);
    }

    ,funcionarioBtnDestroy: function(button) {
        Ext.MessageBox.confirm({
            title          : 'Aviso!'
            ,animateTarget : button.el
            ,msg           : 'Deseja apagar esse registro(s)?'
            ,buttons       : Ext.MessageBox.YESNO
            ,icon          : 'icon-window-question'
            ,scope         : this
            ,fn            : function(btn) {
                if(btn === 'yes') {
                    var store  = button.up('grid').getStore();
                    var record = button.up('grid').getSelectionModel().getSelection();

                    store.getProxy().getWriter().writeAllFields = false;
                    store.getProxy().getWriter().allowSingle    = false;

                    store.remove(record);

                    store.getProxy().getWriter().writeAllFields = true;
                    store.getProxy().getWriter().allowSingle    = true;
                }
            }
        });
    }

    ,funcionarioActionClick: function(view,cell,row,col,e) {
        var rec   = this.getFuncionarioStore().getAt(row);
        var id    = rec.get('id');
        var ativo = !rec.get('ativo');

        rec.set({'id':id, 'ativo': ativo});
    }

    ,funcionarioBtnClearFilters: function(button) {
        this.funcionarioDeselectAll();
        button.up('grid').filters.clearFilters();
    }

    ,funcionarioBtnSave: function(button) {
        var win    = button.up('window'),
            store  = this.getFuncionarioStore(),
            form   = win.down('form'),
            record = form.getRecord(),
            values = form.getValues(false, false, false, true);

        if(form.isValid()) {
            if (!record) {
                record = Ext.create(store.model.modelName);
                record.set(values);
                store.add(record);

            } else {
                record.set(values);
            }

            win.close();
        } else {
            Ext.MessageBox.alert({
                title          : 'Aviso!'
                ,animateTarget : button.el
                ,msg           : 'Digite os dados corretamente!'
                ,buttons       : Ext.MessageBox.OK
                ,icon          : Ext.MessageBox.INFO
            });
        }
    }

    ,funcionarioBtnCancel: function(button) {
        button.up('window').close();
    }
});

Controller Laravel (FuncionarioController.php):

<!--?php class FuncionarioController extends BaseController { 	protected $funcionarios; 	public function __construct(Funcionario $funcionarios) 	{ 		$this--->funcionarios = $funcionarios;
	}

	public function postCreate()
    {
		try {
			$funcionario = $this->funcionarios->fill(Input::json()->all());

			if ($funcionario->save()) {
				$success = true;
				$message = 'Salvo com sucesso!';
			} else {
				$success = false;
				$message = 'Erro';
				$tmp     = array();
				foreach (json_decode($funcionario->errors()) as $mens) {
					$tmp[] = $mens;
				}
				if(count($tmp) > 0) {
					if(isset($tmp[0])){
						$values  = array_values($tmp[0]);
						$message = implode(',', $values);
					}
				}
			}

			return Response::json(array('success' => $success, 'message' => $message), 200);
		} catch (Exception $e) {
			return Response::json(array('success' => false, 'message' => $e->getMessage()), 200);
		}
	}

	public function postRead()
    {
		try {
			$start  = Input::get('start', 0);
			$limit  = Input::get('limit', 50);
			$sort   = Input::get('sort', 'nome');
			$dir    = Input::get('dir', 'ASC');
			$filter = Input::get('filter');

			$funcionarios = $this->funcionarios->orderby($sort, $dir)->skip($start)->take($limit);

			if (is_array($filter)) {
				foreach($filter as $dados) {
					$campo      = $dados['field'];
					$valor      = $dados['data']['value'];
					$tipo       = $dados['data']['type'];
					$comparison = isset($dados['data']['comparison']) ? $dados['data']['comparison'] : '=';

					switch($tipo){
						case 'string' :
							$funcionarios->where($campo, 'LIKE', "%$valor%");
							Break;
						case 'list' :
							if (! strstr($valor, ',')) {
								$valor = '0,'.$valor;
							}
							$valor = explode(',', $valor);
							$funcionarios->whereIn($campo, $valor);
							Break;
						case 'boolean' :
							$valor = (bool) $valor;
							$funcionarios->where($campo, '=', $valor);
							Break;
						case 'numeric' :
							$funcionarios->where($campo, $comparison, $valor);
							Break;
						case 'date' :
							$funcionarios->where($campo, $comparison, $valor);
							Break;
					}
				}

				$array['data']  = $funcionarios->get()->toArray();

				$array['count'] = $funcionarios->count();
			} else {
				$array['data']  = $funcionarios->get()->toArray();
				$array['count'] = $this->funcionarios->all()->count();
			}

			return Response::json($array, 200);
		} catch (Exception $e) {
			return Response::json(array('success' => false, 'message' => utf8_encode( $e->getMessage())), 200);
		}
    }

	public function postUpdate()
    {
		try {
			$records = Input::json()->all();

			if($funcionarios = $this->funcionarios->find($records['id'])) {
				$funcionarios->fill($records);

				if ($funcionarios->save()){
					$success = true;
					$message = 'Salvo com sucesso!';
				} else {
					$success = false;
					$message = 'Erro';
					$tmp     = array();
					foreach (json_decode($funcionarios->errors()) as $mens) {
						$tmp[] = $mens;
					}
					if(count($tmp) > 0) {
						if(isset($tmp[0])){
							$values  = array_values($tmp[0]);
							$message = implode(',', $values);
						}
					}
				}
			} else {
				$success = false;
				$message = 'ID nao existe';
			}
			return Response::json(array('success' => $success, 'message' => $message), 200);
		} catch (Exception $e) {
			return Response::json(array('success' => false, 'message' => utf8_encode( $e->getMessage())), 200);
		}
	}

	public function postDestroy()
    {
		try {
			$records = Input::json()->all();
			$count   = 0;
			$success = false;
			if(is_array($records)){
				$ids     = array();
				foreach($records as $record) {
					$ids[] = $record['id'];
				}

				$count = count($ids);

				if ( $count > 0 ) {
					if($this->funcionarios->whereIn('id', $ids)->delete()){
						$success = true;
					} else {
						$success = false;
					}
				}
			}
			return Response::json(array('success' => $success, 'message' => "Total de registros deletados: $count"), 200);
		} catch (Exception $e) {
			return Response::json(array('success' => false, 'message' => utf8_encode( $e->getMessage())), 200);
		}
	}
}

Model Funcionarios.php

<!--?php use LaravelBook\Ardent\Ardent; class Funcionario extends Ardent { 	public $timestamps = false; 	protected $guarded  = array('id'); 	protected $fillable = array('nome', 'data_nascimento', 'beneficio', 'salario', 'cpf', 'sexo', 'ativo'); 	public static $customMessages = array( 		'required' =--> 'Digite o campo :attribute.',
		'between' => 'O :attribute deve ter no minimo :min digitos'
	);

	public static $rules = array(
		'nome' => 'required|min:5',
		'ativo' => 'required'
	);

	public function beforeSave()
	{
		if($this->isDirty('nome')) {
			$retorno  = array();
			$string   = strtolower(trim(preg_replace("/\s+/", " ", $this->nome)));
			$palavras = explode(" ", $string);

			$retorno[] = ucfirst($palavras[0]);
			unset($palavras[0]);

			foreach ($palavras as $palavra){
				if (!preg_match("/^([dn]?[aeiou][s]?|em)$/i", $palavra)){
					$palavra = ucfirst($palavra);
				}
				$retorno[] = $palavra;
			}
			$this->nome = implode(' ', $retorno);
		}

		if($this->isDirty('beneficio')) {
			$this->beneficio = implode(',', $this->beneficio);
		}
    }
}

exemplo do filtro de pesquisa:

cada campo tem um modo de pesquisa próprio , basta clicar em cima no final de cada coluna como mostra a imagem acima

como falei meu foco não é explicar tudo passo a passo senão esse tutorial iria ficar muito extenso, mas espero que com o exemplo online e o código fonte em mão ajudem vocês a entender um pouco de ExtJS, mas se tiverem duvidas terei o prazer em responder.

exemplo online (podem mexer a vontade):

http://www.extjs.com.br/laravel_extjs/

código fonte completo:

https://[email protected]/fabyo_guimaraes/laravel-extjs.git

  • fhferreira

    Vlw excelente material para quem quer começar com extJs

  • http://www.ressurreto.com Sergio Morais

    Vou utilizar o exemplo para fazer o cadastro de funcionários de um sistema que estou desenvolvendo em laravel 4.1. Já vai uma dúvida: Como faço para obter os dados do combo abaixo de uma tabela no laravel?

    Ext.define(‘LaraExt.view.funcionario.Combo’, {
    extend : ‘Ext.form.field.ComboBox’
    ,alias : ‘widget.funcionariocombo’
    ,editable : false
    ,displayField : ‘valor’
    ,valueField : ‘id’
    ,forceSelection : true
    ,multiSelect : true
    ,mode : ‘local’
    ,triggerAction : ‘all’
    ,listConfig : {
    getInnerTpl : function(val) {
    return ‘ {valor}’;
    }
    }
    ,store: {
    fields: [‘id’, ‘valor’]
    ,data: [
    {id: ‘VT’, valor: ‘Transporte’}
    ,{id: ‘CO’, valor: ‘Odonto’}
    ,{id: ‘CM’, valor: ‘Medico’}
    ]
    }
    });

    • Fabyo

      Ola Sergio
      voce precisa criar uma store dessa tabela e passar o nome dela para o combobox

      • http://www.ressurreto.com Sergio Morais

        Obrigado Fábio.

        • Fabyo

          Se nao conseguir fazer avisa, que eu crio um exemplo pra vc

  • Pedro Henrique

    Otimo topico, isso vai me ajudar e muito sempre tive vontade de mexer com ext mas sempre achei muito complicado, mas vendo seus codigos e olhando o exemplo online esclareceu muito ta de parabens Fabio
    só uma duvida tem como na pesquisa de beneficios por exemplo a lista ser alimentada vinda de uma tabela do banco de dados?
    muito obrigado!

    • Fabyo

      Ola Pedro

      sobre sua duvida da para fazer sim, é parecido com a duvida do Sergio

      voce precisa criar um Store e uma Model e configurar ele

      exemplo:

      {
      type : ‘list’
      ,dataIndex : ‘beneficio’
      ,phpMode : true
      ,store : ‘Beneficio’//Aqui vc passa o nome da store que vc criou
      ,displayField : ‘valor’
      ,valueField : ‘id’
      }

      só seguir o modelo da store e model do exemplo que nao tem erro

  • Edson Babrosa

    Muito legal fazia tempo que não programava … agora com as aulas de vc’s vai ficar facil … espero contribuir em breve

  • Thalles Vinicius

    Muito bacana Fabio, parabéns!
    Você teria algum exemplo usando ExtDirect?

  • Mauro Lucio

    Alguém sabe porque do erro: notfoundhttpexception in routecollection.php line 161?
    Criei uma aplicação e está dando este erro!