paulo-dutra logo

Criando um CRUD no Yii2

Fala galera, no post de hoje iremos falar sobre criação de um CRUD no Yii2, antes disso vamos relembrar o que é um CRUD:

Iremos utilizar o reposítório e o que foi feito nos posts anteriores :

Repositório

Posts:

Para utilizar o que foi feito basta clonar o repositório:

    git clone https://github.com/paulodutra/yii2-posts.git

Após clonar o repositório entre na raiz do projeto e execute o seguinte comando

    composer install 

Como no exemplo anterior já temos a migration necessitamos apenas da criação dos seguintes itens:

Create = Cadastro

Vamos começar pela letra C do CRUD nesse caso o create para isso iremos começar criando a nossa model. mas antes disso logo após a instalação das dependências vá no arquivo config/db.php e altere as configurações de banco de dados(inserindo as suas credenciais). Após as configurações de banco de dados execute as migrations executando o comando abaixo:

   php yii migrate/up

executando-migrations

Depois disso vá a pasta models e crie o seguinte arquivo Clients.php, a principio o nosso modelo irá ficar igual o abaixo:

    <?php

namespace app\models;
use  yii\db\ActiveRecord;

class Clients extends ActiveRecord
{
     /**
     * <b>tableName</b> Método estático que retorna o nome da tabela
     * @return string table
     */
    public static function tableName()
    {
        return 'clients';
    } 

    /**
     * <b>rules</b> Método responsável por realizar a validação dos dados recebidos, 
     * OBS: O tipo safe, informa que as colunas que podem ser informado os dados do formulário (Massive Assignment) atribuição da massiva
     */

     public function rules()
     {
         //informa que os dados podem ser gravados ao utilizar o   $model->attributes no controller
         return [
            [['name', 'email'], 'safe'],
            [['name', 'email'], 'required'],
            [['name', 'email'], 'string', 'max' => 255], 
         ];
     }
}

Note que o modelo herda da classe ActiveRecord(em extends ActiveRecord) classe responsável por implementar o design pattern de mesmo nome, essa classe em conjunto com outras classes responsáveis pela abstração de banco de dados utilizam o PHP Data Objects (PDO), para mais informações veja:

o metódo estático tableName é responsável por retornar o nome da tabela atrelada ao model. Já o método rules é responsável por realizar as validações dos dados recebidos e também por habilitar o Massive Massignment (atribuição massiva) por meio da validação do tipo safe.

OBS: Também é possível criar o modelo utilizando o GII por meio do seguinte comando :

    php yii gii/model --modelClass="Clients" --tableName="clients"

criando-model

Executando esse comando você já irá obter o seu model configurado de acordo com os campos especificados na migration

Para criar o nosso controller e consequentemente o GII(O terminal do Yii Framework) irá criar as views, para isso execute o seguinte comando:

   php yii gii/controller --controllerClass="app\controllers\ClientsController" 

criando-controller-e-views

Note que foi criada uma pasta chamada clients dentro da pasta views e dentro dessa pasta foi criado um arquivo index.php, o mesmo será utilizado posteriormente para a listagem dos nossos registros.

Para facilitar o acesso a rotas vamos criar mais uma opção de menu para isso vá no arquivo: views/layouts/main.php e adicione mais uma opção de menu dentro do de echo Nav::widget no array itens adicionando mais um indice ao mesmo:

     echo Nav::widget([
        'options' => ['class' => 'navbar-nav navbar-right'],
        'items' => [
            ['label' => 'Home', 'url' => ['/site/index']],
            ['label' => 'About', 'url' => ['/site/about']],
            ['label' => 'Contact', 'url' => ['/site/contact']],
            ['label' => 'Clients', 'url' => ['/clients/index']],
            Yii::$app->user->isGuest ? (
                ['label' => 'Login', 'url' => ['/site/login']]
            ) : (
                '<li>'
                . Html::beginForm(['/site/logout'], 'post')
                . Html::submitButton(
                    'Logout (' . Yii::$app->user->identity->username . ')',
                    ['class' => 'btn btn-link logout']
                )
                . Html::endForm()
                . '</li>'
            )
        ],
    ]);

adicionando-clientes-no-menu

Crie um arquivo dentro de views/clients chamado create.php e neste arquivo iremos criar o seguinte formulário:

   <?php
    /* @var $this yii\web\View */
    use yii\helpers\Url;
    
    ?>
    <h1>Novo Cliente</h1>


    <form name="form" method="post" action="<?= Url::to(['clients/create']); ?>">

    <input type="hidden" name="<?= \yii::$app->request->csrfParam; ?>" 
                value="<?= \yii::$app->request->csrfToken; ?>">

        <div class="form-group">
            <label for="name">Nome:</label>
            <input type="text" class="form-control" id="name" name="name" placeholder="Informe o nome">
        </div>
        <div class="form-group">
            <label for="email">email:</label>
            <input type="email" class="form-control" id="email" name="email" placeholder="Informe o email">
        </div>

        <button type="submit" class="btn btn-primary">Enviar</button>
    </form>

Note que antes do formulário propriamente dito, estamos utilizando um helper de URL ** yii\helpers\Url, com a utilização dessa classe conseguimos utilizar o método **Url::to([‘clients/create’]) dentro desse método informamos em um array o nome da controller/método.

Note que criamos um campo do tipo hidden com o nome esse atributo da aplicação (\yii::$app->request->csrfParam;) irá atribuir o nome _csrf e o outro (\yii::$app->request->csrfToken;) irá imprimir o token. Isso serve para evitar ataques do tipo CSRF - Cross-Site Request Forgery (CSRF) onde esse token que foi gerado no nome desse campo se torna uma sessão no servidor e ao enviar o formulário ele verifica se essa seção existe. Isso serve para evitar ataques aonde um site ou outra aplicação que não seja a “sua” forje uma requisição. Para mais informações a respeito de CSRF acesse:

E os demais dados do formulário são relativos aos nomes de campos onde esses nomes são iguais aos nomes definidos na migration e o envio do mesmo

Agora precisamos ir no arquivo controllers/ClientsController e criar o método create. Os métodos no Yii utilizam o o prefixo action antes do nome do método.

    <?php

        namespace app\controllers;

        use app\models\Clients;
        use yii\web\NotFoundHttpException;

        class ClientsController extends \yii\web\Controller
        {

              public function actionIndex()
             {
      
                return $this->render('index');
             }
            
             /**
                * <b>actionCreate</b> Método responsável por realizar a criação de um novo cliente.
                * OBS: Para utilizar $model->attributes, deverá estar habilitado no model dentro do metodo rules os nomes do campo com o valor safe
            */
              public function actionCreate()
              {
                $request = \yii::$app->request;

                if($request->isPost)
                {
                $model = new Clients();

                //attributes é uma propriedade do active record ao passar $request->post() sem parametro exemplo $request->post('email') nem nada ele irá pegar todos os dados do post
                $model->attributes =  $request->post(); 
                //só grava se o metodo rules existir no modelo
                $model->save();           
                return $this->redirect(['clients/index']);

                    }

                return $this->render('create');
             }


            

        }

A primeira linha é um helper de aplicação do Yii que obtém os dados da requisição é armazena o mesmo na váriavel $request depois em $request->isPost ele verifica se a requisição realizada utiliza o verbo http post caso seja verdade significa que é um cadastro, logo após isso é instânciado o modelo $model = new Clients(); e também obtidos os atributos do mesmo $model->attributes.

OBS: Apesar de não termos definidos explicitamente atributos em nosso model, o ActiveRecord obtem os nomes declarados na tabela.

Já o $request->post(); obtem todos os dados submetidos no formulário, e o $model->save(); salva os dados em nosso banco de dados.

Read = Listagem

Após ter realizado o C de nosso CRUD agora esta na hora de implementarmos a letra R, para isso vá no arquivo Agora precisamos ir no arquivo controllers/ClientsController e vá até o método actionIndex:

    <?php
        namespace app\controllers;

        use app\models\Clients;
        use yii\web\NotFoundHttpException;

        class ClientsController extends \yii\web\Controller
        {

            /**
            * <b>actionIndex</b> Método responsável por realizar a listagem dos clientes
            */

            public function actionIndex()
            {
                $clients = Clients::find()->all();

                return $this->render('index', [
                    'clients' => $clients
                ]);
            }


            /**
            * <b>actionCreate</b> Método responsável por realizar a criação de um novo cliente.
            * OBS: Para utilizar $model->attributes, deverá estar habilitado no model dentro do metodo rules os nomes do campo com o valor safe
            */
            public function actionCreate()
            {
                $request = \yii::$app->request;

                if($request->isPost)
                {
                $model = new Clients();

                //attributes é uma propriedade do active record ao passar $request->post() sem parametro exemplo $request->post('email') nem nada ele irá pegar todos os dados do post
                $model->attributes =  $request->post(); 
                //só grava se o metodo rules existir no modelo
                $model->save();           
                return $this->redirect(['clients/index']);

                }

                return $this->render('create');
            }
    ?>

Para obter a listagem de todos os clientes, precisamos de uma instância do model Clients e depois precisamos acessar os métodos Clients::find()->all, ao fazer isso basta armazernar em uma variável e passar em forma de array para o método render return $this->render(‘index’, [‘clients’ => $clients]);

Após a criação do método index no controller, precisamos abrir o arquivo views/clients/index.php e realizar a criação de nossa tabela para a exibição dos dados:

  <?php
    use yii\helpers\Url;
    /* @var $this yii\web\View */
    ?>
    <h1 class="text text-center">Clientes</h1>
    <a href="<?= Url::to(['clients/create']);?>" class="btn btn-success">Novo Cliente</a>
    <table class="table">
        <thead>
        <tr>
            <th>#</th>
            <th>Nome</th>
            <th>Email</th>
            <th>-</th>
        </tr>
        </thead>
        <tbody>
            <?php foreach($clients as $client): ?>
                <tr>
                    <td><?= $client->id; ?></td>
                    <td><?= $client->name; ?></td>
                    <td><?= $client->email; ?></td>
                    <td>
                       - 
                    </td>
                </tr>
            <?php endforeach; ?>
        </tbody>
    </table>

Com isso temos o nosso cadastro e a listagem feita, faltando apenas realizar o teste:

1- Enviando os dados

adicionando-clientes-no-menu

2- Listagem de clientes

cliente-adicionado

Update = Atualização

Agora vamos para a letra U rs! Para isso precisamos ir no arquivo controllers/ClientsController e criar o método update (actionUpdate), diferente do método create esse irá receber por parâmetro o $id do registro que será editado. Para que possamos receber esse parâmetro via url no seguinte formato clients/id/update, precisamos registrar essa rota no arquivo config/web.php php no array rules :

    //configurações anteriores
    'urlManager' => [
            'enablePrettyUrl' => true,
            'showScriptName' => false,
            'rules' => [
                'clients/<id:\d+>/update' => 'clients/update',
            ],
        ],

O <id:\d+> é uma regex que diz que para receber apenas números positivos. Agora o nosso método actionUpdate:

    <?php

    namespace app\controllers;

    use app\models\Clients;
    use yii\web\NotFoundHttpException;

    class ClientsController extends \yii\web\Controller
    {
        //métodos anteriores

        /**
        * <b>actionUpdate</b> Método responsável em realizar a atualização do cliente, recebe o id como parametro (antes disso devera registrar a 
        * personalização de rota no arquivo config/web.php) dentro do array rules
        */
        public function actionUpdate($id)
        {
            $model = Clients::findOne($id);

            if(! $model)
            {
                throw new NotFoundHttpException("Página não encontrada");
            }

            $request = \yii::$app->request;
            
            if($request->isPost)
            {
            //attributes é uma propriedade do active record ao passar $request->post() sem parametro exemplo $request->post('email') nem nada ele irá pegar todos os dados do post
            $model->attributes =  $request->post(); 
            //irá identificar que o registro já existe
            $model->save();
            
            return $this->redirect(['clients/index']);

            }

            return $this->render('update', [
                'model' => $model
            ]);
        }

?>

Veja que ele tem similaridades com o método actionCreate, o que diferencia é que precisamos consultar o id recebido então para isso criamos uma instância do modelo e utilizamos o método findOnde: $model = Clients::findOne($id); Caso o registro não exista iremos retornar uma exceção utilizando uma instância de NotFoundHttpException passando a mensagem. Essa classe irá retornar a mensagem e a página irá ter o status code 404. Conforme imagem apresentada abaixo:

registro-nao-encontrado

O restante do método é bem similar ao método actionCreate.

Para finalizar a funcionalidade precisamos criar o formulário, para isso precisamos criar um arquivo chamado update.php em views/clients:

  <?php
        /* @var $this yii\web\View */
        use yii\helpers\Url;
    ?>
    <h1>Atualizar Cliente</h1>

    <form name="form" method="post" action="<?= Url::to(['clients/update', 'id' => $model->id]); ?>">

    <input type="hidden" name="<?= \yii::$app->request->csrfParam; ?>" 
                value="<?= \yii::$app->request->csrfToken; ?>">

        <div class="form-group">
            <label for="name">Nome:</label>
            <input type="text" class="form-control" id="name" name="name" 
                    placeholder="Informe o nome" value="<?= $model->name; ?>">
        </div>
        <div class="form-group">
            <label for="email">Email:</label>
            <input type="email" class="form-control" id="email" name="email"
                    placeholder="Informe o email" value="<?= $model->email; ?>">
        </div>

        <button type="submit" class="btn btn-primary">Enviar</button>
    </form>

O formulário também é bem similar ao do arquivo create.php, com exceção de carregar o valor atribuido ao registro por meio do value do input, o contéudo da variavel model veio do método render na controller. Para finalizar o editar vá no arquivo views/clients/index.php e adicione na listagem o botão de editar:

    //contéudo anterior
      <tbody>
        <?php foreach($clients as $client): ?>
            <tr>
                <td><?= $client->id; ?></td>
                <td><?= $client->name; ?></td>
                <td><?= $client->email; ?></td>
                <td>
                    <a href="<?= Url::to(['clients/update', 'id' => $client->id]);?>">Editar</a> |
                </td>
            </tr>
        <?php endforeach; ?>
    </tbody>

Delete = Excluir

Enfim chegamos ao D do CRUD. Para isso precisamos registar a rota para que possamos receber o id do registro via parâmetro no seguinte formato clients/id/delete, para isso vá no arquivo: config/web.php :

    //configurações anteriores
    'urlManager' => [
            'enablePrettyUrl' => true,
            'showScriptName' => false,
            'rules' => [
                'clients/<id:\d+>/delete' => 'clients/delete',
            ],
        ],

Agora precisamos criar o nosso método delete (actionDelete), no arquivo controllers/ClientsController.php :

    <?php

        namespace app\controllers;

        use app\models\Clients;
        use yii\web\NotFoundHttpException;

        class ClientsController extends \yii\web\Controller
        {
            //métodos anteriores

            /**
            * <b>actionDelete<b/> Método responsável por excluir um registro, recebe como parametro o id do mesmo como parametro. (antes disso devera registrar a 
            * personalização de rota no arquivo config/web.php) dentro do array rules 
            * 
            */
            public function actionDelete($id)
            {

                $model = Clients::findOne($id);

                if(! $model)
                {
                    throw new NotFoundHttpException("Página não encontrada");
                }

                $model->delete();
                
                return $this->redirect(['clients/index']);
            }

    ?>

Reposítório do Projeto

Bom esse foi o post/tutorial de criação de CRUD no Yii2, lembrando que o Yii possui uma forma mais fácil para criação de CRUD, a mesma iremos ver nos proximos posts. E ai o que achou ? comente abaixo.