Laravel === ###### tags: `php` `estudos` `laravel` # Dicas Preenchimento do formulários com os valores digitados antes do submit * https://laracasts.com/discuss/channels/general-discussion/keeping-input-on-form-validation-request Reaproveitar formulário tanto para criação como edição: * https://laracasts.com/discuss/channels/requests/keep-inputs-after-failed-validation ## Blade Docs * https://laravel.com/docs/master/blade ## Laravel DataBase Migrations * https://laravel.com/docs/master/migrations ## Laravel Eloquent ORM * https://laravel.com/docs/master/eloquent ## Laravel Database * https://laravel.com/docs/master/database ## API para testes... https://swapi.co/ ## Criacao de API baseada em arquivo json https://github.com/typicode/json-server ## Lara Notification -> telegram... composer require laravel-notification-channels/telegram ## exemplo de implementacao de jwt similar ao apresentado em aula... https://medium.com/@aschmelyun/securing-your-laravel-api-with-jwts-in-10-minutes-or-less-9622541244f6 # Dia 01 Para criar um projeto com Laravel: No Linux: `composer create-project laravel/laravel --prefer-dist projeto` ## 1 - Configurar ENV Alterar o arquivo “.env” ### .env ```bash= DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=bdmnlar2 DB_USERNAME=root DB_PASSWORD=coti ``` ## 2 - Criar o banco... ```bash= create database bdmnlar2; use bdmnlar2; ``` ## 3 - Criar Model Criar uma classe... ==php artisan make:model Pessoa== ### 3.1 Pessoa.php ```php= <?php namespace App; use IlluminateDatabaseEloquentModel; class Pessoa extends Model{ protected $fillable= [ 'id','nome','idade' ]; protected $table='pessoas'; } ``` ## 4 - Criar Migration Criar a base da tabela.. ==php artisan make:migration pessoas== ### 4.1 - NossaMigration gerada... ```php= <?php use IlluminateSupportFacadesSchema; use IlluminateDatabaseSchemaBlueprint; use IlluminateDatabaseMigrationsMigration; class Pessoas extends Migration{ //Criando a tabela pessoa com 3 campos ... public function up() { Schema::create('pessoas', function (Blueprint $table){ $table->increments('id'); $table->string('nome',50); $table->integer('idade'); $table->string('endereco',50)->nullable(); $table->timestamps(); }); } public function down() { Schema::drop('pessoas'); } } ``` ### 4.2 - aplicar nossa migration (criando a tabela no banco) ==php artisan migrate== Forçar a execução ==php artisan migrate --force== ou ==php artisan migrate:rollback== Em últimos casos ==php artisan migrate:reset== ou ==php artisan migrate:refresh --seed== ## 5 - Criar Controller Criar o controller: ==php artisan make:controller pessoaController== ### 5.1 - PessoaController.php ```php= <?php namespace AppHttpControllers; use AppPessoa; use IlluminateHttpRequest; class PessoaController extends Controller{ protected $pessoas; public function __construct(Pessoa $pessoas) { $this->pessoas = $pessoas; } //index está buscando todos os dados de pessoa public function index() { //$pessoas = $this->pessoas->paginate(3); $pessoas = $this->pessoas->all(); // olha o nome do blade aqui //return view('pessoas',compact('pessoas')); return view('pessoas', ['pessoas' => $pessoas]); } //Metodo Show (buscar pelo Codigo) public function show($id) { //pessoa (id pre, nome pre, idade pre) //Eloquent $pessoa = $this->pessoas->find($id); //nomedoBlade return view('buscapessoa', compact('pessoa')); } // /form ele irá entrar em Cadastrar ... public function create() { //É uma entrada return view('cadastrar'); } public function posts(Request $request) { //resgata TUDO //dd($request); $request->validate([ 'idade' => 'required|numeric|min:18|max:150', ]); $pessoa = $request->all(); //dd($pessoa); $this->pessoas->create($pessoa); //esta Gravando aqui return redirect()->route('listar')-> with('success', 'Pessoa Cadastrada com Sucesso'); } } ``` --- ## 6 - Adicionar ROTAS Criar as rotas... ### 6.1 - web.php ```php= Route::get('/','PessoaController@index')->name('listar'); Route::get('id/{id}','PessoaController@show')->name('buscar'); Route::get('/form','PessoaController@create')->name('formulario'); Route::post('/salvar','PessoaController@posts')->name('salvarPessoa'); ``` ## 7 - Criar Views VIEWs Criar as telas (views)... ### 7.1 - pessoas.blade.php ```php= <h2>Listagem de Pessoas</h2> <p/> <!--tem sessao se tiver imprime--> @if(session('success')) <div> {{session('success')}} </div> @endif <table border="1"> <tr> <td>Id</td> <td>Nome</td> <td>Endereco</td> <td>Idade</td> <td>Detalhar</td> </tr> @foreach ($pessoas as $p) <tr> <td>{{$p->id}}</td> <td>{{$p->nome}}</td> <td>{{$p->endereco}}</td> <td>{{$p->idade}}</td> <td><a href="{{route('buscar',$p->id)}}">find</a></td> </tr> @endforeach </table> <br/> <a href="{{route('formulario')}}">Cadastrar Pessoa</a> ``` ---- ### 7.2 - cadastrar.blade.php ```php= <!doctype html> <html lang="pt"> <head> </head> <body> <form method="post" action="{{route('salvarPessoa')}}"> @csrf <br/>Nome<br/> <input type="text" name="nome" id="nome" required="required" /> <br/>Idade<br/> <input type="number" name="idade" id="idade" required="required" value="{{old('idade')}}" /> @if ($errors->has('idade')) {{$errors->first('idade')}} @endif <br/>Endereco<br/> <input type="text" name="endereco" id="endereco" required="required" /> <br/> <button type="submit">Enviar os Dados</button> </form> <br/> <a href="{{route('listar')}}">Listar Pessoas</a> </body> </html> ``` ---- ### 7.3 - buscapessoa.blade.php ```php= <h2>Detalhes da Pessoa</h2> <hr/> Id :{{$pessoa->id}}<br/> Nome :{{$pessoa->nome}}<br/> Endereco :{{$pessoa->endereco}}<br/> Idade :{{$pessoa->idade}}<br/> <br/> <a href="{{route('listar')}}">Voltar Listagem</a> ``` ---- ## 8 - Rodar o projeto.. `php artisan serve --port=8888` Digitar a URL passada... http://127.0.0.1:8888/ Criar controller e model... `php artisan make:controller NameController --resource --model=NameModel` --- --- # Dia 02 ## Criado Model clientes ==php artisan make:model Model/Clientes== ```php= <?php namespace App\Model; use Illuminate\Database\Eloquent\Model; class Cliente extends Model { protected $primaryKey = "id"; protected $fillable = [ "nome", "email", "sexo", "idade" ]; protected $table = "clientes"; } ``` ## Criando Migration clientes ==php artisan make:migration clientes== ```php= <?php use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class Clientes extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('clientes', function (Blueprint $table) { $table->Increments('id'); $table->string('nome',50); $table->string('email',100)->unique(); $table->enum('sexo', ['m', 'f']); $table->integer('idade'); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('clientes'); } } ``` ==php artisan migrate== [Campos permitidos para mirations](https://laravel.com/docs/5.8/migrations#columns) ## Se precisar alterar o banco de dados Usa o mesmo arquivo *migrate* e cria a estrutura no novo banco de dados informado no arquivo **/.env**. :::danger :warning: Limpa os dados (Cuidado!!!) ==php artisan migrate:refresh== :warning: Apaga a tabela (Cuidado!!!) ==php artisan migrate:refresh --seed== ::: ## Seeder Procedimento teste para popular com dados randomicos nossa tabela... ==php artisan make:seeder ClientesTableSeeder== ```php= <?php use Illuminate\Database\Seeder; use Illuminate\Support\Str; use Illuminate\Support\Facades\DB; class ClientesTableSeeder extends Seeder { /** * Run the database seeds. * * @return void */ public function run() { DB::table('clientes')->insert([ 'nome' => Str::random(10), 'email' => Str::random(10).'@gmail.com', 'sexo' => 'm', 'idade' => '10' ]); } } ``` ==php artisan db:seed --class ClientesTableSeeder== --- ## Exemplo de migration para ajuste de posicao de campo ==php artisan make:migration add_idade_table_clientes --table=clientes== ```php= <?php use IlluminateSupportFacadesSchema; use IlluminateDatabaseSchemaBlueprint; use IlluminateDatabaseMigrationsMigration; class AddIdadeTableClientes extends Migration { public function up() { Schema::table('clientes', function (Blueprint $table) { $table->integer('idade')->after('email'); }); } public function down() { } } ``` ==php artisan migrate== --- ## Criando controller ClienteController ==php artisan make:controller ClienteController== --- ## Implementando Bootstrap no Lara ```bash= composer require laravel/ui php artisan ui bootstrap npm install && npm run dev ``` --- composer require laravel/ui && php artisan ui bootstrap --auth&& npm install && npm run dev ## Inclusao de idiomas... Baixar repo e incluir em ==resources/lang== https://github.com/caouecs/Laravel-lang ajustar locale dentro do "/config/app.php" --- --- ## Relacionamento Um pra Um... ```bash= php artisan make:model Model/Endereco php artisan make:model Model/Funcionario ``` ```php= <?php namespace App\Model; use Illuminate\Database\Eloquent\Model; class Funcionario extends Model { protected $primaryKey = "id"; protected $fillable = [ 'id', 'nome', 'email' ]; protected $tables = "funcionarios"; public function endereco() { return $this->hasOne(Endereco::class, 'funcionario_id', 'id'); } } ``` ```php= <?php namespace App\Model; use Illuminate\Database\Eloquent\Model; class Endereco extends Model { protected $primaryKey = "funcionario_id"; protected $fillable = [ 'funcionario_id', 'logradouro', 'bairro', 'cidade', 'estado', 'cep' ]; protected $tables = "enderecos"; public function funcionario() { return $this->belongsTo(Funcionario::class, 'funcionario_id', 'id'); } } ``` ```bash= php artisan make:migration funcionarios php artisan make:migration enderecos ``` --- ```php <?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class Funcionarios extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('funcionarios', function (Blueprint $table) { $table->bigIncrements('id'); $table->string('nome', 50); $table->string('email',50)->unique(); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('funcionarios'); } } ``` --- ==php artisan make:controll FuncionarioController --resource== # Exemplo do Controller Ver o método findFuncionario onde aplicamos filtros tanto na tabela principal (funcionarios) a secundária ```php <?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Model\Funcionario; use App\Model\Endereco; use DB; class FuncionarioController extends Controller { protected $funcionarios; public function __construct(Funcionario $funcionarios) { $this->funcionarios = $funcionarios; } /** * Display a listing of the resource. * * @return \Illuminate\Http\Response */ public function index(Request $req) { $lista = $this->funcionarios->all(); //dd($lista); if ($req->session()->has('message')===false) { $req->session()->put("message", "Bem vindo"); } return view('index', [ "funcionarios" => $lista ]); } /** * Show the form for creating a new resource. * * @return \Illuminate\Http\Response */ //Não esquecer do @csrf public function createFuncionario() { return view('createFuncionario'); } /** * Store a newly created resource in storage. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ public function store(Request $request) { //dd($request); $ende=null; $message=null; $request->validate([ 'nome'=>'required|string|max:50|min:2', 'email'=>'email', 'cep'=>'required|string|min:8|max:10', 'logradouro'=>'required', 'bairro'=>'required', 'cidade'=>'required', 'estado'=>'required|string|max:2|min:2', ]); try { DB::beginTransaction(); $funcionario = Funcionario::create([ 'nome' => $request->get('nome'), 'email' => $request->get('email') ]); if ($funcionario) { $ende=$funcionario->endereco()->create([ //'funcionario_id' => $funcionario->attributes['id'], 'logradouro' => $request->get('logradouro'), 'bairro' => $request->get('bairro'), 'cidade' => $request->get('cidade'), 'estado' => $request->get('estado'), 'cep' => $request->get('cep') ]); } if ($funcionario && $ende) { DB::commit(); $message='Funcionário cadastrado com sucesso'; } else { DB::rollBack(); $message='Erro ao cadastrar funcionário'; } return redirect()->route('index')-> with('message', $message); } catch(\Exception $ex) { return redirect()->route('formulario')-> with('message', 'Erro ao criar funcionário: '.$ex->getMessage()); } } public function erros(Reques $ex) { return view('erros'); } /** * Display the specified resource. * * @param int $id * @return \Illuminate\Http\Response */ public function findFuncionario(Request $request) { $request->session()->forget('message'); //dd(Endereco::where('logradouro', '=', 'Rua a')->get() ); $query= $funcs = $this->funcionarios->where('nome', '=', $request->get('buscar')) ->orWhere('email', '=', $request->get('buscar')) ->orWhere('id', '=', $request->get('buscar')) ->orWhereHas('Endereco', function ($query) use ($request) { //dd($request); $query->where('logradouro', '=', $request->get('buscar')); })->get(); /* $funcs = DB::select('select * from funcionarios where nome = ? OR email = ? OR id = ? ', [ $request->get('buscar'), $request->get('buscar'), $request->get('buscar')]); */ $message=''; if (count($funcs)==0) { $message="Não foram encontrados funcionarios para a consulta: " .$request->get('buscar'); $request->session()->put("message", $message); } return view('index', [ "funcionarios" => $funcs ])-> with('message', $message); } /** * Display the specified resource. * * @param int $id * @return \Illuminate\Http\Response */ public function show($id) { // } /** * Show the form for editing the specified resource. * * @param int $id * @return \Illuminate\Http\Response */ public function edit($id) { // } /** * Update the specified resource in storage. * * @param \Illuminate\Http\Request $request * @param int $id * @return \Illuminate\Http\Response */ public function update(Request $request, $id) { // } /** * Remove the specified resource from storage. * * @param int $id * @return \Illuminate\Http\Response */ public function destroy($id) { // } } ``` # Dia 06 ## 1 para muitos - Relacionamentos - hasMany ### Projeto Correntista - Laravel Neste estudo não vamos usar o diretório ==/app/Model== para as nossas classes modelo. Vamos criar seguindo o novo padrão do Laravel que é deixá-las no diretório ==/app== :::info A regra é: - Em casos de poucas models, podemos deixar no local default (==/app==); - para projetos maiores, a fim de uma melhor organização, utilizar a pasta Model(==/app/Model==). ::: Inicialmente teremos duas tabelas, "correntista" e "movimentacoes". A tabela correntista terá realcionamento de um para muitos com a tabela movimentacoes. ```graphviz digraph G { size="5,5" node[shape=record,style=filled,fillcolor=gray95] edge[dir=back, arrowtail=empty] 1[label = "{Correntista|- id\n- nome\n- saldo\n}"] 2[label = "{Movimentacoes|-id\n- operacao\n- valor}"] 1->2 } ``` Seguem os arquivo migrations: **2019_09_16_122315_create_correntistas_table.php** ```php= <?php use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateCorrentistasTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('correntistas', function (Blueprint $table) { $table->increments('id'); $table->string('nome', 50); $table->decimal('saldo', 8 ,2); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('correntistas'); } } ``` **2019_09_16_122326_create_movimentacoes_table** ```php= <?php use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateMovimentacoesTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('movimentacoes', function (Blueprint $table) { $table->increments('id'); $table->string('operacao', 20); $table->double('valor'); $table->integer('correntista_id')->unisigned(); $table->foreign('correntista_id')->references('id')->on('correntistas'); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('movimentacoes'); } } ``` Para cada tabela temos um arquivo de classe (modelo). Segue abaixo: **Correntista.php** ```php= <?php namespace App; use Illuminate\Database\Eloquent\Model; use App\Movimentacao; class Correntista extends Model { protected $primaryKey = "id"; protected $fillable = ['id', 'nome', 'saldo']; protected $table = 'correntistas'; public function movimentacoes() { return $this->hasMany(Movimentacao::class); } } ``` **Movimentacao.php** ```php= <?php namespace App; use Illuminate\Database\Eloquent\Model; use App\Correntista; class Movimentacao extends Model { //Many to One protected $primaryKey = "id"; protected $fillable = ['id', 'operacao', 'valor', 'correntista_id']; protected $table = 'movimentacoes'; //Muitos para um singular (chamando a classe com hasMany) public function correntista() { return $this->belongsTo(Correntista::class); } } ``` ## Criando o controller php artisan make:controller correntistaController ```php= <?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Correntista; use App\Movimentacao; use DB; class CorrentistaController extends Controller { protected $correntistas; public function __construct(Correntista $correntistas) { $this->correntistas = $correntistas; } /** * Display a listing of the resource. * * @return \Illuminate\Http\Response */ public function index(Request $req) { $lista = $this->correntistas->all(); //dd($lista); if ($req->session()->has('message')===false) { $req->session()->put("message", "Bem vindo"); } return view('index', [ "correntistas" => $lista ]); } /** * Display a listing of the resource. * * @return \Illuminate\Http\Response */ public function rest(Request $req) { //$lista = $this->correntistas->all(); //dd($lista); //return json_encode($lista); return response()->json(Correntista::all(), 200); } public function cadastro() { return view('cadastro'); //return view('cadastrar', compact('cliente')); } public function create(Request $req) { $req->validate([ 'nome'=>'required|string|max:50|min:2', 'saldo'=>'required|numeric' ]); //dd($req->id); /* Meu código */ $correntista = $req->all(); $this->correntistas->create($correntista); return redirect()->route('index')-> with('message', 'Correntista cadastrado com sucesso'); } public function deposito($id) { $correntista = $this->correntistas->find($id); return view('deposito', compact('correntista')); } public function retirada($id) { $correntista = $this->correntistas->find($id); return view('retirada', compact('correntista')); } public function depositopost(Request $req) { $movimentacao=null; $message=null; $req->validate([ 'id'=>'required|numeric', 'nome'=>'required|string|max:50|min:2', 'valor'=>'required|numeric|min:1' ]); try { DB::beginTransaction(); $correntista = $this->correntistas->findOrFail($req->get('id')); $movimentacao = Movimentacao::create([ 'operacao' => 'deposito', 'valor' => $req->get('valor'), 'correntista_id' => $req->get('id') ]); if ($movimentacao) { $novoSaldo=($correntista->saldo + $req->get('valor')); //dd($params['id']); $correntista->update(['saldo' => $novoSaldo]); //OU //$correntista = $this->correntistas->findOrFail($req->get('id')); //deposito=$req->valor; //$correntista->saldo = $correntista->saldo + deposito; //$correntista->save(); } if ($movimentacao && $correntista) { DB::commit(); $message='Depósito realizado com sucesso.'; } else { DB::rollBack(); $message='Falha ao registrar depósito.'; } return redirect()->route('index')-> with('message', $message); } catch(\Exception $ex) { return redirect()->route('formulario')-> with('message', 'Falha ao registrar depósito: '.$ex->getMessage()); } } public function retiradapost(Request $req) { $movimentacao=null; $message=null; $req->validate([ 'id'=>'required|numeric', 'nome'=>'required|string|max:50|min:2', 'valor'=>'required|numeric' ]); try { DB::beginTransaction(); $correntista = $this->correntistas->findOrFail($req->get('id')); $movimentacao = Movimentacao::create([ 'operacao' => 'retirada', 'valor' => $req->get('valor'), 'correntista_id' => $req->get('id') ]); if ($movimentacao) { $novoSaldo=($correntista->saldo - $req->get('valor')); //dd($params['id']); $correntista->update(['saldo' => $novoSaldo]); //OU //$correntista = $this->correntistas->findOrFail($req->get('id')); //deposito=$req->valor; //$correntista->saldo = $correntista->saldo + deposito; //$correntista->save(); } if ($movimentacao && $correntista) { DB::commit(); $message='Depósito realizado com sucesso.'; } else { DB::rollBack(); $message='Falha ao registrar depósito.'; } return redirect()->route('index')-> with('message', $message); } catch(\Exception $ex) { return redirect()->route('formulario')-> with('message', 'Falha ao registrar depósito: '.$ex->getMessage()); } } } ``` # Muitos para muitos - Relacionamentos - many2Many Neste projetos usaremos a estrutura de **alunos** e **cursos** onde o relacionamento entre ambos é de muitos para muitos. ```graphviz digraph G { size="5,5" node[shape=record,style=filled,fillcolor=gray95] edge[dir=back, arrowtail=empty] 1[label = "{Alunos|- id\n- nome\n- email\n}"] 2[label = "{Aluno_Curso|-id\n- aluno_id\n- curso_id}"] 3[label = "{Cursos|-id\n- descrição}"] 1->2 2->1 2->3 3->2} ``` --- # DIA 7 ## JWT (Json Web Token) ### Referências [https://jwt.io/](https://jwt.io/) fluxo padrao: ![](https://i.imgur.com/sOvUlUb.png) É um padrão de autenticação que utiliza token Sistema de proteção. Bearer - padrão de autenticação simples - necessita de um token Rota livre - onde se pode fazer o que quiser Rota segura - só entra autenticado ### Início ```bash= php artisan make:model Model/Aluno php artisan make:migration alunos php artisan make:controller AlunoController ``` Editar o arquivo .env com os dados do exemplo. /.env ```bash=9 DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=BDOICOTIREST DB_USERNAME=root DB_PASSWORD=coti ``` App/Model/Aluno.php ```php= <?php namespace App\Model; use Illuminate\Database\Eloquent\Model; class Aluno extends Model { protected $table = 'alunos'; protected $primaryKey = 'id'; protected $fillable = [ 'id', 'nome', 'email', 'password', ]; } ``` ### Instalar JWT no Laravel ```bash= composer require tymon/jwt-auth:1.0.* php artisan vendor:publish --provider="TymonJWTAuthProvidersLaravelServiceProvider" php artisan jwt:secret ``` ### Exemplo de implementação de RateLimit, sendo para esta rota 5 chamadas/minuto autorizado Route::get('/lista','AlunoController@listar')->middleware('throttle:5,1')->name('listagem'); # Exemplo 7 ## Chamadas Rest Pessoa.php ```php= <?php namespace App; use Illuminate\Database\Eloquent\Model; class Pessoa extends Model { protected $table = 'pessoas'; protected $primaryKey = 'id'; protected $fillable = [ 'nome', 'email', 'idade', ]; } ``` web.php ```php= <?php Route::prefix('pessoa') ->middleware('throttle:5,1') ->group(function () { Route::get('/', 'PessoaController@index')->name('index'); Route::get('/{id}', 'PessoaController@findById')->name('find'); Route::post('/', 'PessoaController@store')->name('store'); Route::put('/', 'PessoaController@update')->name('update'); Route::delete('/{id}', 'PessoaController@delete')->name('delete'); }); ``` --- PessoaController.php ```php= <?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Pessoa; class PessoaController extends Controller { protected $pessoas; public function __construct(Pessoa $pessoas) { $this->pessoas = $pessoas; } public function index() { return response()->json(['lista' => Pessoa::all() ],200 ); } public function store(Request $req) { $pessoa = new Pessoa($req->all()); $pessoa->save(); return response()->json(['msg'=>'Store OK','pessoas' => Pessoa::all()]); } public function delete($id) { $pessoa = Pessoa::find($id); $pessoa->delete(); return response()->json(['msg'=>'Delete OK','pessoas' => Pessoa::all()]); } public function update(Request $req) { $pessoa = Pessoa::find($req->input('id')); $pessoa->fill($req->all()); $pessoa->save(); return response()->json(['msg'=>'Update OK','pessoas' => Pessoa::all()]); } public function findById($id) { return response()->json(['pessoa', Pessoa::find($id)], 200); } } ``` --- migration_pessoas.php ```php= <?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class Pessoas extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('pessoas', function (Blueprint $table) { $table->bigIncrements('id'); $table->string('nome'); $table->string('email')->unique(); $table->integer('idade'); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('pessoas'); } } ``` --- --- # Email Mail [http://dontpad.com/emailmail](http://dontpad.com/emailmail) --- --- # Projeto Final ```graphviz digraph G { size="5,5" node[shape=record,style=filled,fillcolor=gray95] edge[dir=back, arrowtail=empty] 1[label = "{Artigo|-id\n- titulo\n- conteudo\n|escritor()}"] 2[label = "{Escritor|- id\n- nome\n- email\n- foto\n|artigos()}"] 3[label = "{ControllerEscritor|+index()\n+ create()\n+ update()\n+ delete()\n}"] 1->2} ``` --- --- ## Criando os modelos php artisan make:model Escritor php artisan make:model Artigo ## Criando as "migrations" para os Banco de dados php artisan make:migration escritores php artisan make:migration artigos ## Criando a Controller php artisan make:controller ControllerEscritor --resource ## Criando a base de dados (MySQL) ```bash= mysql -u root -p mysql> create database COTIOIFINAL; Query OK, 1 row affected (0,02 sec) mysql> use COTIOIFINAL Database changed mysql> ``` .env ```bash DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=COTIOIFINAL DB_USERNAME=root DB_PASSWORD=coti ``` # Arquivos modelos gerados ## Escritor.php ```php= <?php namespace App; use Illuminate\Database\Eloquent\Model; use App\Artigo; class Escritor extends Model { protected $primaryKey = "id"; protected $fillable = [ 'id', 'nome', 'email', 'foto' ]; protected $table = 'escritores'; public function artigos() { return $this->hasMany(Artigo::class); } } ``` ## Artigos.php ```php= <?php namespace App; use Illuminate\Database\Eloquent\Model; use App\Escritor; class Artigo extends Model { //Many to One protected $primaryKey = "id"; protected $fillable = [ 'id', 'titulo', 'conteudo', 'escritor_id' ]; protected $table = 'artigos'; //Muitos para um singular (chamando a classe com hasMany) public function escritor() { return $this->belongsTo(Escritor::class); } } ``` # Arquivos gerados para migration ## 2019_09_18_140150_escritores.php ```php= <?php use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class Escritores extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('escritores', function (Blueprint $table) { $table->increments('id'); $table->string('nome', 50); $table->string('email', 50)->unique(); $table->string('foto', 255); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('escritores'); } } ``` ## 2019_09_18_140155_artigos.php ```php= <?php use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class Artigos extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('artigos', function (Blueprint $table) { $table->increments('id'); $table->string('titulo', 50); $table->longText('conteudo'); $table->integer('escritor_id')->unsigned(); $table->foreign('escritor_id')->references('id')->on('escritores'); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('artigos'); } } ``` ## Adicionar excessao de csrf em App\Http\Middleware\VerifyCsrfToken.php Temos que adicionar esta exceção para que seja possível realizar o post via REST. Para o curso colocamos tudo liberado '*'. ```php=22 protected $except = [ '*' ]; ``` # Arquivo controller: ControllerEscritor.php ```php= <?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Escritor; use App\Artigo; use DB; class ControllerEscritor extends Controller { protected $escritores; public function __construct(Escritor $escritores) { $this->escritores = $escritores; } /** * Display a listing of the resource. * * @return \Illuminate\Http\Response */ public function index() { //Vamos exibir a listagem em JSON return response()->json( [ 'lista' => $this->escritores->all(), 'message' => 'Dados retornados com sucesso' ], 200 ); } /** * Show the form for creating a new resource. * * @return \Illuminate\Http\Response */ public function create() { // } /** * Store a newly created resource in storage. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ public function store(Request $request) { DB::beginTransaction(); try{ //Vamos verificar se o escritor já existe $escritor = $this->escritores ->where('email', $request->email) ->first(); if (!isset($escritor)) { $escritor = new Escritor(); //Solução do Woney usa o método fill ($escritor->fill($request->all())); $escritor->nome = $request->input("nome"); $escritor->email = $request->input("email"); $escritor->foto = $request->input("foto"); $escritor->save(); } //return response()->json(['message' => $escritor], 200); $artigo = new Artigo(); //Solução do Woney usa o método fill ($escritor->fill($request->all())); $artigo->titulo = $request->input("titulo"); $artigo->conteudo = $request->input("conteudo"); $escritor->artigos()->save($artigo); DB::commit(); return response()->json(['message' => 'Dados gravados'], 200); } catch (\Exception $e) { DB::rollback(); return response()->json( ['message' => 'Erro ao gravar os dados: '.$e->getMessage()] , 200 ); } } /** * Display the specified resource. * * @param int $id * @return \Illuminate\Http\Response */ public function show($id) { // } /** * Show the form for editing the specified resource. * * @param int $id * @return \Illuminate\Http\Response */ public function edit($id) { // } /** * Update the specified resource in storage. * * @param \Illuminate\Http\Request $request * @param int $id * @return \Illuminate\Http\Response */ public function update(Request $request) { $escritor = $this->escritores->find($request->input('id')); if (isset($escritor)) { $escritor->fill($request->all()); $escritor->save(); $message='Dados atualizados'; } else { $message = 'Registro não encontrado'; } return response()->json(['message' => $message], 200); } /** * Remove the specified resource from storage. * * @param int $id * @return \Illuminate\Http\Response */ public function delete($id) { $escritor = $this->escritores->find($id); if (isset($escritor)) { $escritor->delete(); $message = 'Dados apagados'; } else { $message = 'Registro não encontrado'; } return response()->json(['message' => $message], 200); } } ``` # Arquivo de rotas "web.php" ```php= <?php Route::prefix('api') ->middleware('throttle:5,1') ->group(function () { Route::get('/', 'ControllerEscritor@index')->name('escritor.lista'); Route::get('/{id}', 'ControllerEscritor@show')->name('escritor.show'); Route::post('/', 'ControllerEscritor@store')->name('escritor.create'); Route::put('/', 'ControllerEscritor@update')->name('escritor.update'); Route::delete('/', 'ControllerEscritor@delete')->name('escritor.delete'); }); ``` ### Exemplos de relacionamentos Laravel. ```php= // Relacionamento 1 para 1 class Usuario extends Eloquent { public function conta() { return $this->hasOne('Conta'); } } class Conta extends Eloquent { public function usuario() { return $this->belongsTo('Usuario'); } } // Relacionamento 1 para N class Estado extends Eloquent { public function cidades() { return $this->hasMany('Cidade'); } } class Cidade extends Eloquent { public function estado() { return $this->belongsTo('Estado'); } } // Relacionamento N para N class Pessoa extends Eloquent { public function cidades() { return $this->belongsToMany('Cidade'); } } class Cidade extends Eloquent { public function pessoas() { return $this->belongsToMany('Pessoa'); } } ```