A finalidade essencial de qualquer aplicação web é receber requisições do usuário e entregar respostas usado o protocolo http(s)
1: Baixa curva de aprendizado, boa documentação, forte comunidade. Evolução lenta, novo recurso demoraram para ser introduzidos: ex: novos design patterns, composer, namespaces ...
2: Evoluíram com a linguagem, mas sempre tiveram perspectiva enterprise e são lack community
2011: Laravel - O melhor dos dois mundos.
2013: Laravel 4 - com componentes do symfony e outras libs externas. Publicação de suas próprias libs como componentes independentes no composer. Exemplo: Illuminate/Eloquent
Laravel foi pensado para chamar a "atenção": Illuminate, spark, artisan, elegant, eloquent, elixir etc
Vantagens no uso de componentes:
Framework:
Implementaremos as camadas MVC para manipular os dados desse schema:
Recursos modernos de PHP tem mais requisitos de máquina que o velho PHP, o que consequentemente dificulta o deploy.
From: Laravel: Up & Running - An O'Reilly book by Matt Stauffer
Instale o Virtualbox em seu SO:
https://www.virtualbox.org/wiki/Downloads
Importar .ova com tudo que é necessário para os treinamentos:
https://uspdev.github.io/treinamentos
PPA do ondrej:
sudo add-apt-repository -y ppa:ondrej/php
sudo apt-get update
Libs mínimas para rodar o Laravel:
php7.2 php7.2-xml php7.2-intl php7.2-mbstring php7.2-mysql
Instalação do composer globalmente:
curl -s https://getcomposer.org/installer | php
sudo mv composer.phar /usr/local/bin/composer
sudo apt-get install -y git
Configurações globais:
git config --global user.name "joazinho"
git config --global user.email "joaozinho@usp.br"
sudo apt -y install mysql-server
Criando usuário e banco:
sudo mysql
CREATE DATABASE disciplinas;
GRANT ALL PRIVILEGES ON disciplinas.* to disciplinas@'localhost' identified by 'disciplinas';
quit
Criação do projeto com composer:
composer create-project laravel/laravel meu_projeto
Se estiver tudo correto:
php artisan serve
Exemplo:
Route::get('/', function() {
return 'gritar!';
});
Route::get('/{n}', function($n) {
$as = str_repeat('a',$n);
return "grit{$a}r!";
});
Criação da classe básica do controller:
php artisan make:controller IndexController
Encaminhar requisição na rota para controller:
Route::get('/','IndexController@gritar');
Route::get('/{n}','IndexController@gritarMultiplo');
Agora, mover código da closure para os controller.
No método do controller, retornar uma view:
return view('gritar');
Criar o arquivo resources/views/gritar.blade.php:
<h1>Gritar</h1>
Adicionar remote upstream
git remote add upstream URL
Atualizar remotes
git remote update
Fazer merge do master do upstream com master local
git checkout master
git merge upstream/master
Criação de Resource para Disciplinas, com model, controller e migrations (criar exemplos com o tinker)
Configurar .env com info do bd. Gerar model, controller, resource e migrations para Disciplina:
php artisan make:model Disciplina -crm
Editair migrations e inserir campos para titulo e ementa:
$table->string('titulo');
$table->text('ementa');
Rodar migrations:
php artisan migrate
Cadastrar disciplinas usando tinker:
php artisan tinker
Cadastre:
Implementação do método index
Rota resource e rota adicional para raiz do sistema:
Route::get('/','DisciplinaController@index');
Route::resource('disciplinas','DisciplinaController')
Implementar método index do controller disciplina:
return Disciplina::all();
Agora usando view:
return view('disciplinas.index',['disciplinas' => $disciplinas]);
Template para listar disciplinas:
# resources/views/disciplinas/index.blade.php
<ul>
@foreach ($disciplinas as $disciplina)
<li>{{ $disciplina->titulo }} </li>
@endforeach
</ul>
Qual você prefere?
1: ['disciplinas' => $disciplinas]
2: compact('disciplinas')
Implementar método show, ou seja, criação de página que mostra a disciplina e sua ementa
Implementar o método show para disciplina:
return view('disciplinas.show',compact('disciplina'));
Template para show:
<h1>{{ $disciplina->titulo }}</h1>
<p>{{ $disciplina->ementa }}</p>
Link em index.blade.php
<a href="/disciplinas/{{ $disciplina->id }}">
Criação de formulário para cadastro de disciplina. Persistir
Criar um formumário html para cadastro de disciplina:
<form method="POST" action="/disciplinas">
{{ csrf_field() }}
Nome: <input name="titulo">
Ementa: <textarea name="ementa"> </textarea>
<button type="submit"> Salvar </button>
</form>
No método create retornar o formulário:
return view('disciplinas.create');
Checar rota para submissão (já criada):
php artisan route:list
No método store, salvar no banco de dados:
$disciplina = new Disciplina;
$disciplina->titulo = $request->titulo;
$disciplina->ementa = $request->ementa;
$disciplina->save();
return redirect('/');
Agora podemos colocar um botão no index.blade.php para cadastrar nova disciplina. Do it!
Criação de formulário para edição de disciplina. Persistir
Formulário para editar disciplina:
<form method="POST" action="/disciplinas/{{ $disciplina->id }}">
{{ csrf_field() }}
{{ method_field('patch') }}
Nome: <input name="titulo" value="{{ $disciplina->titulo }}">
Ementa: <textarea name="ementa"> {{ $disciplina->ementa }} </textarea>
<button type="submit"> Salvar </button>
</form>
Renderizar formulário no método edit:
return view('disciplinas.edit',compact('disciplina'));
Persistir mudança no método update:
$disciplina->titulo = $request->titulo;
$disciplina->ementa = $request->ementa;
$disciplina->save();
return redirect("/disciplinas/$disciplina->id");
Em index.blade.php inserir link de edição de disciplina:
<a href="/disciplinas/{{ $disciplina->id }}/edit"> Editar </a>
Implementar opção de delete de disciplina. Mostrar botão no index
Fazer um formumlário de delete em index.blade.php:
<form method="POST" action="/disciplinas/{{ $disciplina->id }}">
{{ csrf_field() }}
{{ method_field('delete') }}
<button type="submit">Apagar</button>
</form>
Implementar o método destroy:
$disciplina->delete();
return redirect('/');
Criar model e migrations para Turmas
Criar o model para cadastro de turma:
php artisan make:model Turma -m
Inserir os campos na migration:
$table->string('ministrante');
$table->date('inicio');
$table->date('fim');
$table->text('bibliografia')->nullable();
$table->integer('disciplina_id')->unsigned();
$table->foreign('disciplina_id')->references('id')->on('disciplinas');
Rodar migrations:
php artisan migrate
Implementar relacionamento entre os Model de Turma e Disciplina. Testar novos métodos no Tinker
No model Turma:
public function disciplina()
{
return $this->belongsTo('App\Disciplina');
}
No model de Disciplina:
public function turmas()
{
return $this->hasMany('App\Turma');
}
tinker:
$d = new Disciplina;
$d->ementa = 'Filosofia Grega e Romana'
$d->titulo = "Filosofia I"
$d->save()
$t = new Turma;
$t->ministrante = 'Pedro'
$t->inicio = '2015-10-10'
$t->fim = '2016-10-10'
$t->disciplina_id = $d->id
$t->save()
$d->turmas
$d->turmas[0]->ministrante
$t->disciplina
$t->disciplina->ementa
Criação de formulário para cadastro de turma no contexto da disciplina. Persistir
No controler de disciplina, método para inserção de turma:
public function createTurma($disciplina_id)
{
return view('disciplinas.turmas.create',compact('disciplina_id'));
}
Rota para inserir turma:
Route::get('/disciplinas/{disciplina_id}/turmas/create','DisciplinaController@createTurma');
Botão para inserir turma no show de disciplina:
<a href="/disciplinas/{{ $disciplina->id }}/turmas/create">Inserir Turma</a>
Formulário para cadastro de turma:
<form method="POST" action="/disciplinas/{{ $disciplina_id }}/turmas">
{{ csrf_field() }}
Ministrante: <input name="ministrante">
Data início: <input name="inicio">
Data fim: <input name="fim">
Bibliografia: <textarea name="bibliografia"></textarea>
<button type="submit" class="btn btn-success"> Salvar </button>
</form>
Criar uma rota para store de turma:
Route::post('/disciplinas/{disciplina}/turmas','DisciplinaController@storeTurma');
Criar o método store turma:
public function storeTurma(Request $request,Disciplina $disciplina)
{
$turma = new \App\Turma;
$turma->ministrante = $request->ministrante;
$turma->inicio = $request->inicio; #desafio! Receber dd/mm/YYYY
$turma->fim = $request->fim; #desafio: idem
$turma->bibliografia = $request->bibliografia;
$turma->disciplina_id = $disciplina->id;
$disciplina->turmas()->save($turma);
return redirect("/disciplinas/$disciplina->id");
}
Listar as turmas cadastradas nas páginas das disciplinas
Mostrar as turmas, no show da disciplina:
@foreach ($disciplina->turmas as $turma)
{{ $turma->ministrante }}
{{ $turma->inicio }}
@endforeach
Implementar autenticação de usuário local. Restringir acesso de cadastro de turma e disciplina para usuários logados.
Autenticação:
php artisan make:auth
Deixar os métodos index e show públicos e os demais privados.
public function __construct()
{
$this->middleware('auth')->except(['index','show']);
}
Inserir botão de login no master.blade.php
@auth
<form id="logout-form" action="/logout" method="POST">
{{ csrf_field() }}
<button type="submit">Sair </button>
</form>
@else
<a href="/login">Login</a>
<a href="/register">Register</a>
@endauth
Implementar busca por nome da disciplina
Buscar:
public function search(Request $request)
{
$text = $request->text;
$disciplinas = Disciplina::where('titulo', 'LIKE', "%{$text}%")->get();
return view('disciplinas.index',compact('disciplinas'));
}
Rota:
Route::post('/disciplinas/search','DisciplinaController@search');
Campo de busca no template master:
<form method="POST" action="/disciplinas/search">
{{ csrf_field() }}
<input name="text" type="text">
<button type="submit"> Buscar </button>
</form>
Deixar método search público.
Criar o template master usando um exemplo do Bootstrap 4. Fazer todos outros templates herdarem o estilo do template master
Adaptar o layout de exemplo do bootstrap 4:
sticky-footer-navbar -> master.blade.php
Limpar conteúdo e criar uma seção content:
@section('content')
@show
Atualizar node:
curl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash -
sudo apt-get install -y nodejs linpng-dev
Instalar dependências do npm:
npm install
Geração de assets com mix:
mix.styles([
'node_modules/bootstrap/dist/css/bootstrap.css',
'resources/assets/css/app.css',
],'public/assets/app.css');
mix.js([
'node_modules/jquery/dist/jquery.min.js',
'node_modules/bootstrap/dist/js/bootstrap.js',
'resources/assets/js/app.js',
], 'public/assets/app.js');
Compilação dos assets:
npm run dev
Colocar links no master.blade.php:
<link href="/assets/app.css" rel="stylesheet">
<script src="/assets/app.js"></script>
Fazer todos templates herdarem master:
@extends ('master')
@section ('content')
seu conteúdo
@endsection
Em especial, alterar:
Implementar calendário do tipo datepicker (jquery ou bootstrap) nos campos de data início e fim do cadastro de turma
Adicionar bootstrap-datepicker em packages.json:
npm install bootstrap-datepicker
Autoload para Jquery em webpack.mix.js:
mix.autoload({
'jquery': ['jQuery', '$'],
})
Adicionar método datepicker em uma classe css:
$('.datepicker').datepicker();
No controller, tratar data recebida:
Carbon::createFromFormat('m/d/Y',$request->inicio);
Dica para input: autocomplete="off"
Configuração do calendário em pt-BR:
$('.datepicker').datepicker({
format: 'dd/mm/yyyy',
language: 'pt-BR'
});
Arquivo com as traduções em pt-BR:
bootstrap-datepicker/js/locales/bootstrap-datepicker.pt-BR.js
Que tal ordernar turmas pela data de início?
@foreach ($disciplina->turmas->sortByDesc('inicio') as $turma)
Usando carbon no blade:
{{ Carbon\Carbon::parse($turma->inicio)->format('d/m/Y') }}