Baixe o app para aproveitar ainda mais
Prévia do material em texto
Ementa Ementa Introdução ao Livro Nota Ambiente Suporte: Como tirar as dúvidas? Versão Atualizada Erros Quem Sou Eu? Prefácio Database Introdução Configuração Configurando o SQLite Configurando MySQL Várias Conexões Migrations Gerando Arquivos de Migrations Padrão de Tabelas Estrutura Rodar Migrations Reverter Migrations Rollback e Migration Deletar e Criar Novamente Tabelas Criando Novas Tabelas Renomear e Deletar Tabelas Colunas Modificar Colunas Índices Criando índices Tipos de índices disponíveis Tamanho índices (MySQL / MariaDB) Renomear índices Deletar índices Chave estrangeira (Foreign Key) Deletar chave estrangeira (foreign key) Database: Seeding Introdução Criando uma Seeder Definindo um Usuário Padrão Rodar Seeders Factories Relacionamento de tabelas Eloquent Introdução Criar Models Padrões af://n0 Nomes de Tabelas Chave Primária Timestamps Models Listando os registros Filtros Inserir Mass Assignment Editar Deletar Filtrar e excluir Excluir pela chave primária Soft Deleting Utilizando o Recurso de Soft Deleting Incluindo Registros Deletados Recuperando Apenas os Deletados Restaurando Deletar Permanentemente Outras Opções firstOrCreate firstOrNew updateOrCreate Comparando Models Eloquent Relacionamentos de Tabelas Eloquent Relationships One to One One to One Inverso Inserir Simplificando Consultas Eloquent Relationships One to Many Definir o relacionamento One to Many Simplificando Consultas Inserindo avaliações Editar avaliação Eloquent Relationships Many to One Eloquent - Many to Many Criar os Relacionamentos Exibindo os registros relacionados Recuperar dados tabela pivô Timestamps Vincular registros Many to Many Toggle Atualizar Registro Tabela Pivô Eloquent Relationships - Eager Loading Nested Eager Loading Colunas Especificas Constraining Eager Loads Lazy Eager Loading Eloquent Relationships - Touching Parent Timestamps Eloquent Collections Collections disponíveis all() get() count() avg() average() max() min() median() first() firstWhere() last() has() prepend() push() put() pop() where() whereStrict() whereIn() whereInStrict() whereNotIn() whereNotInStrict() sort() sortBy() sortByDesc() groupBy() Eloquent Mutators Data Mutators Eloquent Escopos Locais Dinâmicos Globais Aplicando Escopo Global Globais Anônimos Remover Escopos Globais Remover Todos os Escopos Globais Eloquent Eventos Introdução Exemplo Prático Observadores Database - Query Builder Introdução Buscando Registros no Banco de Dados Recuperando todos os registros Recuperando um Registro Recuperar Valor Específico de uma Coluna Recuperando os Valores de Algumas Colunas Consultas Agregadas Expressões SQL brutas Métodos brutos selectRaw whereRaw / orWhereRaw havingRaw / orHavingRaw orderByRaw Parâmetros nomeados Joins Inner Join Left Join Cross Join Joins Avançado Sub-Query Joins (sub consulta) Unions Cláusulas Where where orWhere whereBetween whereNotBetween whereIn whereNotIn whereNull whereNotNull whereDate whereMonth whereDay whereYear whereTime whereColumn Agrupamento de Parâmetros whereExists Where JSON Inserir JSON Filtrar JSON whereJsonContains whereJsonLength Cláusulas condicionais Ordenar Consultas Ordenar por mais recentes Ordenar por mais antigos Ordenar aleatóriamente groupBy / having Paginação manual Inserir Inserir json Atualizar Atualizar JSON Incrementar Decrementar Deletar Outros Assuntos Consultas SQL brutas (Raw SQL) Selecionar Inserir Editar Deletar Executando uma declaração geral Transações de banco de dados Introdução Deadlocks Manual Paginação Query Builder Eloquent Paginação Simples Customizar URL Anexando Parâmetros Paginar APIs ( JSON) Customizar Paginação Métodos disponíveis Query Builder vs Eloquent ORM vs Raw SQL Eloquent Query Builder Raw SQL Desempenho Concluindo O que vem agora? Ao adquirir este livro pelas vias legais você recebeu os dados de acesso a nossa plataforma ead, diretamente no seu e-mail (confere na caixa de SPAMs). Introdução ao Livro Nota Primeiramente, deixo uma nota sobre a pirataria. Infelizmente nem todos os profissionais tem seus valores bem definidos e um caráter fortalecido para cumprir com os deveres morais como cidadão de bem. Portanto, se comprou/baixou este livro fora de algum site/pagina/canal NÃO vinculado à EspecializaTi, por favor, nos notifique o quanto antes, para que possamos tomar as medidas necessários contra a pirataria (meu contato pessoal e direto é: carlos@especializati.com.br). Ambiente Criar um ambiente de desenvolvimento para o PHP é um desafio, especialmente porque temos diversas opções, e em alguns sistemas operacionais o desafio é ainda maior. Portanto, para criar algo mais dinâmico e visual, a primeira etapa deste livro está disponível na plataforma ead, logo o primeiro passo é criar o seu ambiente para trabalhar com o Laravel seguindo os passos citados lá. Nesse curso inicial além de criar o ambiente mostro como realizar os testes práticos do livro, como dá os seus primeiros passo, enfim, tudo o que precisa para tirar o máximo proveito deste livro está descrito lá. Suporte: Como tirar as dúvidas? Acho muito interessante a ideia de comprar um livro técnico (como este) e poder contar com o suporte do autor do livro para aplicar os exemplos práticos, porque dessa forma torna a leitura mais agradável e evita perder tempo com eventuais problemas. Enfim, toda e qualquer dúvida que você tiver que esteja relacionada com o tema deste livro basta postar na plataforma ead, que responderei o mais rápido possível. Conta comigo! Versão Atualizada Se tiver um bom tempo que já baixou este livro sugiro que baixe a versão atualizada na plataforma ead, porque este livro estará sempre recebendo atualizações e correções de erros, fazendo assim você sempre terá acesso as atualizações deste livro. af://n4 af://n5 mailto:carlos@especializati.com af://n9 af://n16 af://n20 Erros Esse livro ainda está na sua primeira edição, como não usei nenhuma editora para publicar todo o processo de escrita, correção de erros e etc ficou em minhas mãos, portanto, caso encontre QUALQUER erro ortográfico, ou qualquer tipo de erro, ou algo que pode ser melhorado, por favor, me envie imediatamente para o meu e-mail: carlos@especializati.com.br Quem Sou Eu? Meu nome é Carlos Ferreira, atuo com desenvolvimento de sistemas web/mobile há 9 anos, e desde 2014 estou ensinando profissionais como obter os melhores resultados possíveis com o Laravel. Já ajudei milhares de profissionais em todo o mundo. Meu canal do YouTube (segundo a última contagem) já ultrapassou mais 1.419.960 de visualizações, e 90% de todo o conteúdo é Laravel. Possuo algumas certificações: Comptia Linux +, LPI, Novell Certification. Prefácio O Laravel é um framework que já não precisa provar mais nada, já está muito conceituado e amplamente aceito, e cada dia que passa sua popularidade aumenta cada vez mais e mais. É muito comum ver grandes/pequenas/médias empresas adotarem o Laravel também. Já perdi as contas de quantas vezes empresas me procuraram para ter consultoria porque iriam migrar velhos sistemas para o Laravel. Essa popularidade toda do Laravel não é atoa, muito menos mera coincidência, o Laravel é uma framework que faz por merecer todos os seus resultados, possui todos os méritos. As comunidades do Laravel são extremamente ativas, e amigáveis em contribuir e ajudar, isso sem dúvidas é mais um grande diferencial. Os profissionais envolvidos com o framework fazem justiça ao Laravel, porque são extremamente competentes, e tudo isso é refletido no framework. Se você tiver curiosidade observe o core do Laravel, e veja a qualidade do código e das implementações, realmente é tudo muito bem pensado. Sinceramente, nunca vi um projeto com um nível de capricho tão grande como este, cada detalho foi pensado e planejado para obter o melhor resultado possível. Neste livro descrevo os recursos de manipulação de banco de dados do Laravel, e já dá para ter ideia o quanto o Laravel é poderoso,e ao mesmo tempo respeita a sua principal característica, que é ser simples. af://n24 mailto:carlos@especializati.com af://n28 af://n33 Recurso Descrição default (String) É a conexão padrão que será usada para conectar a aplicação ao banco de dados connections (Array) Dados de acesso a todas as conexões migrations (String) Nome da tabela que controla os arquivos de migrations que já foram executados em nossa aplicação (Mais detalhes no capitulo sobre migrations) redis (Array) Dados de configuração do Redis (O Redis é um armazenamento de chave e valor de código aberto, rápido e avançado), o Redis pode ser utilizado para trabalhar com cache. Database Introdução Um dos pontos fortes do Laravel é justamente sua capacidade de interação com bancos de dados, além de possuir recursos avançados, provê métodos extremamente simples para lidar com diferentes bancos de dados. Atualmente, o Laravel possui suporte para quatro bancos de dados, sendo eles: MySQL PostgreSQL SQLite SQL Server Configuração As configurações de database ficam localizadas no arquivo config/database.php . Neste arquivos podemos definir todas as conexões, e também devemos definir qual é a conexão padrão. Antes de continuar falando mais sobre as configurações é importante entendermos todos as opções disponíveis no arquivo de configuração config/database.php . af://n43 af://n45 af://n58 af://n80 NOTA: Helpers são funções globais disponíveis em todos os locais da aplicação Laravel, essas funções (conhecidas como helpers) são extremamente úteis, e provem recursos que facilitam o nosso desenvolvimento com o framework. NOTA: O Helper env() faz a leitura de variáveis de ambiente definidas no arquivo .env, essa função recebe dois argumentos, o primeiro é o nome da variável que será feito a leitura no arquivo .env, e o segundo argumento é o valor padrão caso essa variável não exista ou esteja com o valor em branco. Configurando o SQLite Caso o banco de dados que for utilizar seja o SQLite o primeiro passo é criar o arquivo que será utilizado para armazenar os dados, para isso rode o comando: Uma vez que já temos o arquivo que armazenará os dados da nossa aplicação o próximo passo é informar no arquivo config/database.php que o banco de dados que iremos trabalhar é o SQLite, portanto precisamos alterar a conexão padrão para sqlite : Ou, também podemos deixar que o Helper env() leia o arquivo .env, neste caso podemos deixar no arquivo config/database.php assim: E no arquivo .env precisamos alterar a variável de ambiente DB_CONNECTION para sqlite Agora que já definimos que o nosso banco de dados será o SQLite no arquivo config/database.php , no array connections precisamos atualizar os dados de acesso ao banco: touch database/database.sqlite 'default' => 'sqlite' 'default' => env('DB_CONNECTION', 'mysql'), DB_CONNECTION=sqlite 'sqlite' => [ 'driver' => 'sqlite', 'database' => env('DB_DATABASE', database_path('database.sqlite')), 'prefix' => '', 'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true), ], af://n80 Configuração Descrição driver (String) Drive que o PDO utiliza para acessar bases de dados SQLite. database (String) Path (caminho) onde está localizado o arquivo que será utilizado para armazenar os dados (os registros). O Helper database_path() aponta justamente para o diretório database/ da aplicação. prefix (String) Caso suas tabelas possuam algum prefixo (semelhante ao Wordpress: wp_) é possível setar qual é o prefixo utilizado em suas tabelas. foreign_key_constraints (Boolean) Restrições de chave estrangeira (foreign key). Essa configuração ajuda a manter a integridade de dados relacionais. Configurando MySQL Caso o banco de dados que for utilizar seja o MySQL o primeiro passo é informar que a conexão defalt (padrão) é mysql, portanto, no arquivo config/database.php em default vamos definir a conexão como mysql: No arquivo .env: Essa configuração vai fazer a leitura do array mysql dentro de connections no arquivo de configuração config/database.php : 'default' => env('DB_CONNECTION', 'mysql'), DB_CONNECTION=mysql 'mysql' => [ 'driver' => 'mysql', 'host' => env('DB_HOST', '127.0.0.1'), 'port' => env('DB_PORT', '3306'), 'database' => env('DB_DATABASE', 'forge'), 'username' => env('DB_USERNAME', 'forge'), 'password' => env('DB_PASSWORD', ''), 'unix_socket' => env('DB_SOCKET', ''), 'charset' => 'utf8mb4', 'collation' => 'utf8mb4_unicode_ci', 'prefix' => '', 'prefix_indexes' => true, 'strict' => true, 'engine' => null, af://n115 Configuração Descrição driver (String) Drive que o PDO utiliza para acessar bases de dados MySQL. host (String) Endereço de IP ou nome do host com a base de dados MySQL port (Int) Porta que está rodando o banco de dados. database (String) Nome do banco de dados. username (String) Usuário de acesso ao banco de dados password (Any) Senha de acesso ao banco de dados charset (String) charset de condificação de caracteres collation (String) Collation (Colação) nada mais é que a codificação de caracteres existente no banco de dados. prefix (String) Caso suas tabelas possuam algum prefixo (semelhante ao Wordpress: wp_) é possível setar qual é o prefixo utilizado em suas tabelas. Algumas das principais configurações são lidas a partir do helper env(), portanto, precisamos atualizar no arquivo .env os dados de acesso ao nosso banco de dados MySQL: Várias Conexões Um recurso muito interessante do Laravel é alternar entre diferentes conexões com uma simplicidade muito grande, a facade DB permite fazer isso, veja o exemplo: A conexão precisa estar configurada no arquivo config/database.php e listada em connections , porque a facade DB vai usar exatamente essas informações para alternar a conexão e fazer o que tiver que ser feito, seja buscar os registros, inserir novos e etc. ], DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=livro_laravel DB_USERNAME=root DB_PASSWORD=root // Não esquece: use DB; $users = DB::connection('pgsql')->get(); af://n158 O último exemplo vai fazer a leitura do arquivo de configuração config/database.php e buscar as informações de conexão em connection de pgsql , ou seja, vai retornar todos os usuários na base de dados PostgreSQL. 'pgsql' => [ 'driver' => 'pgsql', 'host' => env('DB_HOST', '127.0.0.1'), 'port' => env('DB_PORT', '5432'), 'database' => env('DB_DATABASE', 'forge'), 'username' => env('DB_USERNAME', 'forge'), 'password' => env('DB_PASSWORD', ''), 'charset' => 'utf8', 'prefix' => '', 'prefix_indexes' => true, 'schema' => 'public', 'sslmode' => 'prefer', ], Migrations O recurso de Migrations permite gerenciar as tabelas do banco de dados. Com este recurso é possível criar as tabelas, alterar a estrutura, definir a ordem de criação de cada tabela e fazer relacionamentos entre elas. Os arquivos de migrations (estrutura das tabelas) ficam em database/migrations/ Grandes empresas possuem departamentos específicos para lidar com bancos de dados, nestes casos os recursos de migrations não são utilizados, justamente porque existem profissionais para lidar com toda a responsabilidade de banco de dados, portanto, não fica a cargo do Laravel lidar com a criação das tabelas e ordem de criação. Mas, uma das vantagens de trabalhar com o recurso de migrations para criar as tabelas é justamente centralizar toda a estrutura do banco de dados, trabalhar em equipe neste caso é mais fácil, porque toda a estrutura do banco de dados está centralizada, e também a ordem das tabelas, relacionamentos e etc, tudo está organizado e, pode ser compartilhado em equipe. Gerando Arquivos de Migrations Para criar um novo arquivo de migration usa o comando do artisan make:migration: Existe um padrão recomendado para gerar arquivos de migrations, o nome do arquivo deve preceder o prefixo create_ e no finalprecisa ter o nome _table. Se o objetivo é criar um tabela chamada por exemplo products, o nome do arquivo de migration deve ser create_products_table: Os arquivos de migrations ficam armazenados por default (padrão) em database/migrations/ , cada arquivo de migration contém no início do nome um timestamps (data e hora), e é justamente esse nome que é usado para definir a ordem de criação das tabelas. Os arquivos de migrations com o timestamps mais antigo são gerados primeiramente, seguindo essa ordem. Mas, tenho uma tabela que precisa vir antes de todas, como ordernar para que ela seja criada primeiramente? Você pode renomear o timestamps manualmente do arquivo de migration correspondente a tabela. Mas, uma ação é extremamente importante, sempre que altera algum arquivo de migration manualmente precisa rodar esse comando para o composer mapear novamente os arquivos de migrations: php artisan make:migration create_tablename_table php artisan make:migration create_products_table composer dump-autoload af://n166 af://n172 Quando cria um arquivo de migration chamado create_products_table por default o mecanismo de migrations do Laravel entende que a tabela correspondente é products, porém, em alguns casos pode ser necessário ter uma tabela com um nome diferente do arquivo de migration, para esses casos podemos usar as options --table ou --create para indicar o nome da tabela, exemplo: No exemplo anterior embora o o arquivo de migration indique que o nome da tabela é products, no exemplo indicamos que o nome da tabela será produtos, e não products, como é por default. A opção --create especifica que vamos criar uma nova tabela. A opção --table é usado para alterar a estrutura default de alguma tabela já existente, ou para adicionar colunas extras. Outra opção é o --path, essa opção permite especificar um path (caminho/diretório) diferente do default, ou seja, caso queira uma estrutura de arquivos de migrations personalizada, pode usar a opção --path para especificar, exemplo: Uma maneira mais prática e popular de criar os arquivos de migrations é combinando o comando que cria o model (veremos mais sobre Models adiante, não se preocupe). Esse comando já cria o arquivo de model + o arquivo de migration correspondente: php artisan make:model Models\\Product -m A opção -m que garante que o arquivo de migration create_products_table seja criado também. Padrão de Tabelas Por padrão o Laravel já trás pré-definido dois arquivos de migrations, um para a tabela de users (usuários) e outro para a tabela password_resets , que é usada justamente para validar e recuperar a senha do usuário. Caso a tabela de usuários precise de outras colunas além das padrões, podemos adicionar. Estrutura As classes de migrations contém básicamente dois métodos, o up e o down. O método up é usado normalmente para adicionar novas tabelas, com colunas e índices no database. Enquanto o método down é utilizado para reverter as operações realizadas no método up. Ou seja, se usou o método up para criar um nova tabela com a sua estrutura de colunas, o método down pode ser usado para deletar a tabela. php artisan make:migration create_products_table --create=produtos php artisan make:migration create_roles_table --path=database/migrations af://n197 af://n202 Vamos criar a estrutura da tabela de products, já com algumas colunas, mais adiante aprenderemos mais sobre os tipos de colunas possíveis: use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateProductsTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('products', function (Blueprint $table) { $table->increments('id'); $table->string('name'); $table->text('description'); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::drop('products'); } } A classe Schema possui o método estático create, que espera dois parâmetro obrigatórios, sendo eles: o primeiro o nome da tabela, e o segundo uma função de callback para definir a estrutura de colunas da tabela. Por default a classe de migration traz definido duas colunas: $table->increments('id'); $table->timestamps(); A primeira definição cria uma coluna chamada id, que será a chave primária da tabela products, e ainda é autoincrement (o seu valor auto incremental). $table->increments('id'); Os padrões do Laravel recomenda que essa coluna se chame id, mas, não há problema algum caso queira renomear e deixar algum nome "mais coerente", algo como product_id. A opção timestamps cria duas colunas na tabela products, uma chamada created_at que registra exatamente e automaticamente o valor do timestamps (data/hora/minutos/segundos) sempre que um novo registro é inserido. E também cria uma coluna chamada updated_at que registra exatamente e automaticamente o valor do timestamps (data/hora/minutos/segundos) sempre que o registro é atualizado. Mais adiante detalharemos um pouco mais sobre as demais colunas, e outras opções. Rodar Migrations Uma vez que definimos a estrutura da nossa tabela no arquivo de migration correspondente o próximo passo é acessar o projeto pelo terminal e rodar o comando que cria as tabelas, para isso rode o comando: php artisan migrate Ao rodar esse comando cria todas as tabelas definidas pelos arquivos de migrations em database/migrations/ Se observar o database além das tabelas definidas nesse diretório de migrations, criou uma tabela adicional chamada "migrations", essa tabela serve justamente para controlar qual(is) arquivos de migrations já foram rodados e criou-se as tabelas a partir deles. Essa tabela é muito importante porque caso rode novamente o comando anterior não tentará criar novamente a mesma tabela, justamente porque na tabela "migrations" tem o histórico do que já rodou, e em qual sequência foi criado. Em produção em alguns casos será necessário forçar o comando, para criar as tabelas a partir dos arquivos de migrations, e para conseguir tal feito precisa combinar a opção --force: php artisan migrate --force Reverter Migrations af://n221 af://n231 Se observar na tabela de migrations notará que ela possui uma coluna chamada "batch", essa é uma coluna com valor inteiro, e ela armazena exatamente a sequência que a migration foi criada, ou seja, se criar um tabela agora e rodar o comando o valor será 1, se criar um novo arquivo de migration e rodar novamente o valor dos próximos arquivos de migrations serão 2, e assim sucessivamente. O próximo comando está ligado justamente com esse valor. Para conseguir testar deixe primeiramente apenas os arquivos de migrations default (users e password_resets) e rode o comando: php artisan migrate Isso vai criar essas duas tabelas, e na tabela migrations o valor de batch estará como 1 para ambas. Agora crie o arquivo de migration para a tabela de products, e rode novamente o comando para criar a tabela. Após fazer isso, pode observar que a tabela migrations o valor de batch para esse novo arquivo de migration está com 2. Para reverter (fazer o roll back) das últimas migrations criadas podemos rodar o comando: php artisan migrate:rollback Isso vai desfazer as últimas tabelas criadas. Em alguns casos será necessário voltar não apenas 1 passo, ou seja, desfazer apenas as últimas migrations, mas também desfazer algumas sequências anteriores, para isso podemos combinar a opção --step e especificar quantos passos queremos voltar: php artisan migrate:rollback --step=3 Outra alternativa é fazer o roll back em todas as nossas migrations, para isso podemos usar o comando: php artisan migrate:reset Após rodar esse comando não existirá nenhuma tabelaem seu banco de dados, exceto a tabela migrations e sem conteúdo. Quando rodamos esses comandos de roll back o método down dos nossos arquivos de migrations entram em cena, e no caso, deleta a tabela. Rollback e Migration Agora vamos imagina que a nossa tabela products precisa de uma nova coluna, chamada por exemplo "featured" para indicar se o produto é destaque ou não, podemos adicionar essa nova coluna na tabela através do método up na classe de migration: af://n250 [...] public function up() { Schema::create('products', function (Blueprint $table) { $table->increments('id'); $table->string('name'); $table->text('description'); $table->boolean('featured')->default(false); $table->timestamps(); }); } [...] Se observar o banco de dados a estrutura do arquivo de migration não está coerente com a tabela, precisamos resolver isso. Uma das alternativas é fazer o roll back (porque precisamos deletar essa tabela) e recriar novamente com a nova estrutura, uma das alternativas é rodar estes dois comando, o primeiro deleta as tabelas e próximo recria: php artisan migrate:reset php artisan migrate Ou podemos rodar simplesmente o comando que deleta as tabelas (execulta o método down das classes de migrations) e recria novamente (executa o método up das classes de migrations): php artisan migrate:refresh Assim como o comando migrate:rollback, no comando migrate:refresh também podemos especificar quantos passos queremos aplicar o comando, usando a opção --step: php artisan migrate:refresh --step=3 Deletar e Criar Novamente O comando migrate:fresh vai deletar todas as tabelas do database e recriar novamente (esse comando não passa pelo método down dos classes de migrations, ele simplesmente deleta todas as tabelas e recria novamente): php artisan migrate:fresh af://n262 af://n268 Tabelas Criando Novas Tabelas Para criar novas tabelas usa o método estático create da facade Schema. O método create recebe dois argumentos, o primeiro é o nome da tabela, enquanto o segundo é uma Closure (função de callback) com um objeto de Blueprint, exemplo: Schema::create('products', function (Blueprint $table) { $table->increments('id'); $table->timestamps(); }); É possível verificar se a tabela já existe, antes de criar, exemplo: public function up() { // Só caso ainda não exista a tabela if (!Schema::hasTable('products')) { Schema::create('products', function (Blueprint $table) { $table->increments('id'); $table->string('name'); $table->text('description'); $table->timestamps(); }); } } Também é possível usar o método hasColumn para verificar se uma coluna já existe na tabela, exemplo: if (Schema::hasColumn('products', 'name')) { // } Outra alternativa possível da facade Schema é não usar a conexão default ao banco de dados, e sim usar o método connection para indicar outra conexão que deseja aplicar ao usar essa migration: Schema::connection('nome_conexao')->create('users', function (Blueprint $table) { $table->increments('id'); $table->timestamps(); }); No momento de criar uma nova tabela é possível definir algumas opções para a tabela, exemplo: af://n268 af://n269 Recurso Descrição $table->engine = 'InnoDB'; Especifica a engine de armazenamento (Para bancos de dados MySQL) $table->charset = 'utf8mb4'; Especifica as configurações de caracteres padrão (Para bancos de dados MySQL) $table->collation = 'utf8mb4_unicode_ci'; Especifica a collation padrão para a tabela (Para bancos de dados MySQL) $table->temporary(); Cria uma tabela temporária (Exceto para SQL Server) Um cuidado muito importante deve ser levado em conta no momento de renomear uma tabela, se ela tiver chaves estrangeiras (foreign key) ao renomear pode perder a referencia da chave estrangeira, e isso causa um grande problema. Renomear e Deletar Tabelas O método down da classe de migration pode ser usado para deletar uma tabela, ou em alguns casos até mesmo renomear. Para renomear uma tabela podemos usar o método rename da facade Schema: Schema::rename($oldName, $newName); Schema::rename('products', 'produtos'); Outra alternativa é deletar uma tabela, no caso podemos usar o método drop: Schema::drop('products'); Outra alternativa para deletar, porém mais segura é usando método dropIfExists, porque esse método antes de efetivamente deletar a tabela checa se realmente ela existe: Schema::dropIfExists('products'); Colunas af://n301 af://n314 O schema builder do Laravel contém uma grande variedade de opções de colunas para construir suas tabelas. Recurso Funcionalidade $table->bigIncrements('id'); Auto-incrementing UNSIGNED BIGINT (primary key) equivalent column. $table->bigInteger('votes'); Coluna BIGINT. $table->binary('data'); Coluna BLOB. $table->boolean('confirmed'); Coluna BOOLEAN. $table->char('name', 100); Coluna CHAR com tamanho opcional. $table->date('created_at'); Coluna DATE (data). $table->dateTime('created_at'); Coluna DATETIME (data e hora). $table->dateTimeTz('created_at'); Coluna DATETIME (com fuso horário). $table->decimal('amount', 8, 2); Coluna DECIMAL com precisão (total de digitos) e escala (dígitos decimais). $table->double('amount', 8, 2); Coluna DOUBLE com precisão (total de digitos) e escala (dígitos decimais). $table->enum('level', ['easy', 'hard']); Coluna ENUM. $table->float('amount', 8, 2); Coluna FLOAT com precisão (total de digitos) e escala (dígitos decimais). $table->geometry('positions'); Coluna GEOMETRY. $table->geometryCollection('positions'); Coluna GEOMETRYCOLLECTION. $table->increments('id'); Coluna auto incremental UNSIGNED INTEGER (chave primária). $table->integer('votes'); Coluna INTEGER. $table->ipAddress('visitor'); Coluna para endereço de IP. $table->json('options'); Coluna para armazenamento JSON. $table->jsonb('options'); Coluna JSONB. $table->lineString('positions'); Coluna LINESTRING. $table->longText('description'); Coluna LONGTEXT. $table->macAddress('device'); Coluna endereço de IP MAC. $table->mediumIncrements('id'); Coluna auto incremental UNSIGNED MEDIUMINT (chave primária). $table->mediumInteger('votes'); Coluna MEDIUMINT. $table->mediumText('description'); Coluna MEDIUMTEXT. $table->morphs('taggable'); Adiciona a coluna taggable_id UNSIGNED BIGINT e taggable_type VARCHAR, para relacionamentos polimórficos. $table->multiLineString('positions'); Coluna MULTILINESTRING. $table->multiPoint('positions'); Coluna MULTIPOINT. $table->multiPolygon('positions'); Coluna MULTIPOLYGON. Recurso Funcionalidade $table->nullableMorphs('taggable'); Adiciona as colunas como nullable (null) para morphs() . $table->nullableTimestamps(); Alias para o método timestamps() . $table->point('position'); Coluna POINT. $table->polygon('positions'); Coluna POLYGON. $table->rememberToken(); Adiciona a coluna remember_token VARCHAR(100), com valor padrão NULL. $table->smallIncrements('id'); Auto-incrementing UNSIGNED SMALLINT (primary key) equivalent column. $table->smallInteger('votes'); Coluna SMALLINT. $table->softDeletes(); Adiciona a coluna deleted_at TIMESTAMPS, com valor padrão NULL, para o recurso de soft deletes. $table->softDeletesTz(); Adiciona a coluna deleted_at TIMESTAMPS (com fuso horário), com valor padrão NULL, para o recurso de soft deletes. $table->string('name', 100); Coluna VARCHAR com tamanho opcional. $table->text('description'); Coluna TEXT. $table->time('sunrise'); Coluna TIME (horário). $table->timeTz('sunrise'); Coluna TIME (com fuso horário). $table->timestamp('added_on'); Coluna TIMESTAMP. $table->timestampTz('added_on'); Coluna TIMESTAMP (com fuso horário). $table->timestamps(); Adiciona as colunas created_at e a coluna updated_at TIMESTAMPS, com valor padrão de NULL. $table->timestampsTz(); Adiciona as colunas created_at e a coluna updated_at TIMESTAMPS(com fuso horário), com valor padrão de NULL. $table->tinyIncrements('id'); Coluna auto incremental UNSIGNED TINYINT (chave primária). $table->tinyInteger('votes'); Coluna TINYINT. $table->unsignedBigInteger('votes'); Coluna UNSIGNED BIGINT. $table->unsignedDecimal('amount', 8, 2); Coluna UNSIGNED DECIMAL com precisão (total de digitos) e escala (dígitos decimais). $table->unsignedInteger('votes'); Coluna UNSIGNED INTEGER. $table->unsignedMediumInteger('votes'); Coluna UNSIGNED MEDIUMINT. $table->unsignedSmallInteger('votes'); Coluna UNSIGNED SMALLINT. $table->unsignedTinyInteger('votes'); Coluna UNSIGNED TINYINT. $table->uuid('id'); Coluna UUID. $table->year('birth_year'); Coluna YEAR (ano). Modificar Colunas É possível também alterar colunas das tabelas através dos arquivos de migrations, ou seja, toda ou parte da estrutura de uma tabela pode ser modificada, caso haja necessidade. Para alterar a tabela de products por exemplo, podemos criar um novo arquivo de migration e definir qual ou quais colunas queremos alterar, rode este comando para criar um novo arquivo de migration para alterar a estrutura da tabela products: php artisan make:migration create_products_table --table=produtos No método up do novo arquivo de migration vamos especificar que a coluna "description" não é obrigatório o preenchimento, portanto, vamos definir essa coluna como valor null: Schema::table('products', function (Blueprint $table) { $table->string('description')->nullable(); }); Segue uma lista com todos as possibilidades para modificar colunas de tabelas, inclusive com modificadores de índice: af://n490 Modificador Descrição ->after('column') Ordena a coluna após outra coluna especifica (MySQL) ->autoIncrement() Define coluna INTEGER com incremento automático (chave primária) ->charset('utf8') Especifica o conjunto de caracteres para a coluna (MySQL) ->collation('utf8_unicode_ci') Especifica a collation da coluna (MySQL/SQL Server) ->comment('my comment') Adiciona um comentário a coluna (MySQL) ->default($value) Especifica um valor padrão para a coluna ->first() Define como a primeira coluna da tabela (MySQL) ->nullable($value = true) Permite que valores NULL sejam inseridos na coluna, e o valor padrão é NULL ->storedAs($expression) Cria uma coluna de armazenamento (MySQL) ->unsigned() Define a coluna INTEGER como UNSIGNED (MySQL) ->useCurrent() Define que a coluna TIMESTAMP use CURRENT_TIMESTAMP (timestamps atual) como valor padrão ->virtualAs($expression) Cria uma coluna virtual (MySQL) ->generatedAs($expression) Cria uma coluna de identidade com opções de sequência especificadas (PostgreSQL) ->always() Define a precedência de valores de sequência sobre entrada para uma coluna de identidade (PostgreSQL) Índices Criando índices O schema builder possui suporte para vários tipos de índices. Uma das possibilidades é definir que os valores da coluna são únicos, para isso podemos encadear o método unique na definição da coluna: $table->string('title')->unique(); Outra alternativa é definir a coluna como índice após definir: af://n547 af://n548 Método Descrição $table->primary('id'); Define uma chave primária $table->primary(['id', 'parent_id']); Define chaves compostas $table->unique('email'); Define um índice único (valo único) $table->index('state'); Define um índice simples $table->spatialIndex('location'); Define um índice spatial. (Exceto para SQLite) $table->string('title'); $table->unique('title'); O Laravel gera automaticamente um nome para o índice, porém, podemos passar um segundo argumento no método unique e customizar o nome do índice: $table->unique('title', 'unique_title'); Tipos de índices disponíveis Cada método de índice do schema builder aceita um segundo argumento opcional, que pode ser usado justamente para definir um nome customizado para o índice. Quando não informa este segundo argumento no método unique por padrão o usa-se o nomedatabela_nomedacoluna_recurso Tamanho índices (MySQL / MariaDB) A partir da versão 5.4 o Laravel adotou o charset utf8mb4 como padrão, que possui suporte para armazenar "emojis" no banco de dados. Porém, isso trouxe alguns "problemas", em bancos de dados MySQL <= 5.7.7 e bancos de dados MariaDB <= 10.2.2 para colunas com índices precisa limitar o tamanho, o limite máximo suportado por essas versões para campos com índices é 191. Para resolver isso, uma das soluções mais práticas é definir a quantidade padrão de caracteres para as colunas, isso pode ser feito no Provider AppServiceProvider ( app/Providers/AppServiceProvider.php ), no método boot inclua essa configuração: af://n559 af://n582 Método Descrição $table->dropPrimary('users_id_primary'); Deleta a chave primária da tabela users. $table->dropUnique('users_email_unique'); Deleta o índice único da tabela users. $table->dropIndex('geo_state_index'); Deleta o índice da tabela "geo". $table->dropSpatialIndex('geo_location_spatialindex'); Deleta o índice spatial da tabela "geo" (Exceto para SQLite). /** * Bootstrap any application services. * * @return void */ public function boot() { // Não esquece: use Illuminate\Support\Facades\Schema; Schema::defaultStringLength(191); } Renomear índices Para renomear um índice pode usar o método renameIndex , este método aceita no primeiro argumento o nome atual do índice, e o segundo argumento é novo nome para o índice: $table->renameIndex('old_name', 'new_name') Deletar índices Para deletar um índice precisa usar o método correspondente ao índice criado, e indicar o seu nome. Por padrão, o Laravel automaticamente identifica o índice pelo padrão nomedatabela_nomedacoluna_recurso, veja algumas opções: Ou, podemos simplesmente passar um array com o nome convencional do índice (prefiro desta forma, mais simples): Schema::table('users', function (Blueprint $table) { $table->dropPrimary(['user_id']); // Deleta o índice de chave primária 'users_id_primary' $table->dropUnique(['email']); // Deleta o índice único 'users_email_unique' }); af://n587 af://n592 Chave estrangeira (Foreign Key) Felizmente o Laravel também possibilita criar chaves estrangeiras. Resumidamente, chaves estrangeiras (foreign key) são usadas para restringir e forçar a integridade dos registros relacionados em diferentes tabelas. Vamos fazer algo bastante prático, vamos usar a nossa tabela products adicionar uma nova coluna chamada user_id e vamos ligar o valor dessa coluna com a coluna id da tabela users . Essa coluna user_id seria por exemplo id do usuário que é responsável pelo produto. Podemos alterar a estrutura da nossa tabela products de duas formas, uma delas é criar um arquivo de migration para fazer isso, com o comando: php artisan make:migration add_user_id_to_users_table --table=products Porém, particularmente não gosto dessa opção, justamente porque teremos mais de um arquivo de migration que trabalha com a mesma tabela, com o tempo isso pode deixar desorganizado a nossa aplicação. A outra alternativa é adicionar a nova coluna na estrutura do arquivo de migrations atual (create_products_table), e fazer o refresh da tabela. É exatamente essa opção que vamos seguir. Veja como fica o método up: public function up() { Schema::create('products', function (Blueprint $table) { $table->increments('id'); $table->unsignedInteger('user_id'); $table->string('name'); $table->text('description'); $table->timestamps(); $table->foreign('user_id')->references('id')->on('users'); }); } Observe, primeiramente adicionamos a coluna user_id como UNSIGNET e INTEGER (inteira): $table->unsignedInteger('user_id'); E após definimos a coluna user_id como chave estrangeira, referenciando a coluna id da tabela users: $table->foreign('user_id')->references('id')->on('users'); af://n615 Também é possível definir aação desejada, com o método onDelete, ou com o método onUpdate. No exemplo vamos definir: "on delete cascade", essa configuração ajuda a manter a integridade dos registros, e evita registros órfãos no banco de dados, porque se deletar um usuário por exemplo, vai deletar automaticamente todos os produtos ligados a este usuário. $table->foreign('user_id') ->references('id')->on('users') ->onDelete('cascade'); Após redefinir a estrutura da tabela products, podemos atualizar, para isso no terminal rode o comando: php artisan migrate:refresh Deletar chave estrangeira (foreign key) Para deletar uma chave estrangeira podemos usar o método dropForeign . As chaves estrangeiras também usam o mesmo padrão de nomes que os índices, por padrão concatena nomedatabela_nomedacoluna_recurso. Veja o exemplo para deletar a chave estrangeira da tabela de products: $table->dropForeign('products_user_id_foreign'); Ou, podemos simplesmente passar um array com o nome convencional da chave estrangeira (prefiro desta forma, mais simples): $table->dropForeign(['user_id']); Também podemos habilitar ou desabilitar restrições de chaves estrangeiras em nossas migrations, usando os seguintes métodos: Schema::enableForeignKeyConstraints(); Schema::disableForeignKeyConstraints(); af://n634 Database: Seeding Introdução Outro recurso extremamente útil do Laravel é o de Seeder. Para exemplificar como esse recurso pode ser útil irei citar um exemplo. Imagine que desenvolvemos uma aplicação com Laravel e terminamos de fazer o deploy (hospedar) o app em um servidor, e nesse nosso sistema tem uma área restrita, ou seja, apenas pessoas autenticadas podem acessar. O que fazer para acessar? Simples, neste caso podemos utilizar o recurso de Seeder, com este recurso é possível definir algumas rotinas pré-configuradas para manipular banco de dados. Neste caso, é possível criar uma Seeder com os dados de um usuário padrão para ter acesso ao sistema. As classes de Seeder do Laravel ficam em database/seeds/ Criando uma Seeder Para criar uma nova Seeder no Laravel é bem simples, é possível utilizar o próprio artisan para criar a classe, neste caso vamos criar uma Seeder para criar um novo usuário em nosso sistema. Veja o comando: php artisan make:seeder UsersTableSeeder Esse comando vai gerar a classe em database/seeds/UsersTableSeeder.php Definindo um Usuário Padrão Agora que criamos nossa classe de Seeder podemos abrir e criar uma lógica para inserir um novo usuário, na classe UsersTableSeeder, o método run() deve conter a lógica para criar o novo usuáro, veja como fica: use Illuminate\Database\Seeder; use App\User; class UsersTableSeeder extends Seeder { /** * Run the database seeds. * * @return void */ af://n644 af://n645 af://n654 af://n659 public function run() { User::create([ 'name' => 'Carlos Ferreira', 'email' => 'carlos@especializati.com.br', 'password' => bcrypt('MinhaSenhaAqui'), ]); } } Agora que criou a classe de Seeder para inserir um novo usuário, o próximo passo é registrar essa nova Seeder, para isso abra a classe DatabaseSeeder ( database/seeds/DatabaseSeeder.php ) e registre a nova classe: public function run() { $this->call(UsersTableSeeder::class); } No método run() deve ficar a lógica onde registra todas as Seeders, lembrando que pode ter várias chamadas de diversas Seeders (pode ter quantas seeders for necessário). O método $this->call() pode ser invocado várias vezes para registrar várias Seeders, ou pode também receber um array com a Seeders a serem executadas: public function run() { $this->call([ UsersTableSeeder::class, // ProductsTableSeeder::class, ]); } Rodar Seeders Uma vez que criou a classe de Seeder, e registrou o próximo passo é simplesmente rodar e criar o novo registro, em nosso caso irá criar um novo usuário, para isso rode este comando: php artisan db:seed Caso tenha várias classes de Seeder registradas em DatabaseSeeder é possível especificar qual exatamente é para executar, para isso use a opção --class : php artisan db:seed --class=UsersTableSeeder af://n670 Neste caso mesmo que tenha várias classes de Seeders registradas vai rodar apenas a UsersTableSeeder . Também é possível criar as Seeders no momento que criar as tabelas através do recurso de migration, veja como: php artisan migrate:refresh --seed Este comando vai recriar as tabelas e automaticamente rodas as Seeders registradas. Factories Em ambiente de desenvolvimento em muitos casos é interessante inserir um grande volume de registros nas tabelas para realizar testes de forma mais real. Porém, usar o recurso de Seeder para inserir estes registros embora seja funcional, não é nada prático. Podemos neste caso usar o recurso de factories e automatizar a inserção dos registros nas tabelas. Neste exemplo vamos inserir 50 produtos automaticamente, primeiramente precisamos criar a classe de Factory, para isso rode o comando: php artisan make:factory ProductFactory Os arquivos de factories ficam armazenados em database/factories . Também é possivel já adiantar o nosso trabalho, já vinculando o Factory ao model correspondente, no caso ao model de Product (este model está em app/Models/), para isso basta usar a opção --model : php artisan make:factory ProductFactory --model=Models\\Product O novo arquivo foi gerado em database/factories/ProductFactory.php , com o seguinte conteúdo: use Faker\Generator as Faker; $factory->define(App\Models\Product::class, function (Faker $faker) { return [ // ]; }); O método define recebe dois argumentos, o primeiro é o model (com o namespace), e o segundo argumento é uma função callback, que recebe como parâmetro um objeto de Faker , e é justamente essa classe que contém todos os recursos que precisamos para automatizar o processo de definição de valores para o que será inserido em nossa tabela, no caso, na tabela products (porque estamos utilizando o model Product). af://n683 Vamos definir a estrutura de inserção de registros na tabela de products de acordo com as limitações dessa tabela, veja como fica: use App\Models\Product; use Faker\Generator as Faker; $factory->define(Product::class, function (Faker $faker) { return [ 'user_id' => 1, 'name' => $faker->unique()->name, 'description' => $faker->paragraph, 'featured' => false, ]; }); Neste último exemplo definimos que a tabela products a coluna name será gerado um valor aleatório, porém único. Para a coluna description também um valor aleatório com uma quantidade de caraceters maior, e a coluna featured receberá um valor padrão de false, para todos os registros. Existem centenas de opções e combinações possíveis para inserir valores aleatórios no banco de dados utilizando o recurso de factory. Caso queira saber mais opções, sugiro que dê uma olhada nas propriedades possíveis e comentadas na classe que está em vendor/fzaninotto/faker/src/Faker/Generator.php (não pode alterar nada em vendor/, porém é totalmente valida a curiosidade de observar a implementação dos recursos). Simplesmente ter a classe de Factory pronta não resolve nada, precisamos fazer a chamada dela e especificar quantos registros queremos criar aleatóriamente, no caso, vamos inserir 50 produtos. Precisamos criar um novo seeder chamado ProductsTableSeeder : php artisan make:seeder ProductsTableSeeder O arquivo foi gerado em database/seeds/ProductsTableSeeder.php Para fazer a utilização da Factory ProductFactory precisamos usar o helper factory no método up do seeder: use Illuminate\Database\Seeder; class ProductsTableSeeder extends Seeder { /** * Run the database seeds. * * @return void */ public function run() {factory(App\Models\Product::class, 50)->create(); } } NOTA: Como estamos usando um model (Product) (assunto que será abordado mais adiante) precisamos criar o model, para isso rode o comando: NOTA: Antes de rodar o seeder para criar o factory com os produtos dinamicamente, como estamos trabalhando com o Model (que será abordado mais detalhadamente mais adiante), precisa criar um atributo chamado `$fillable` com um array com os nomes das colunas no model `Product` (`app/Models/Product.php`): Observe que precisamos passar dois argumentos na função (helper) factory. O primeiro é model correspondente, este primeiro parâmetro é muito importante, pois a identificação de qual Factory será chamado é justamente pelo model. O segundo parâmetro é a quantidade de registros é para inserir, no caso 50. O método create que foi encadeado, é para indicar a ação, no caso, inserir novos registros. Se o objetivo for por exemplo criar dinâmicamente um único registro, pode fazer desta forma: $user = factory(App\User::class)->make(); php artisan make:model Models\\Product protected $fillable = ['user_id', 'name', 'description', 'featured']; Por último só precisamos configurar o Seeder ProductsTableSeeder na classe DatabaseSeeder ( database/seeds/DatabaseSeeder.php ): public function run() { $this->call([ UsersTableSeeder::class, ProductsTableSeeder::class, ]); } Para finalizar, resta apenas testar. Rode o comando para rodar os Seeders configurados, e observe que na tabela products irá inserir 50 registros com valores aleatórios, após rodar o comando: php artisan db:seed --class=ProductsTableSeeder Passamos a opção --class para rodar apenas o seeder ProductsTableSeeder , porque já rodamos o seeder UsersTableSeeder em outra oportunidade. Relacionamento de tabelas A tabela products na última alteração (no módulo de migrations) adicionamos a coluna user_id que é justamente para relacionar o usuário ao produto, sendo este usuário o responsável pelo produto. Portanto, ao rodar o exemplo acima está faltando algo, pois a coluna user_id precisa ser preenchida com algum valor, mais precisamente com algum valor de ID da tabela de users. Com o recurso de factories também é possível inserir dados relacionados, no exemplo a seguir vamos inserir cinco novos usuários, e já vincular 25 produtos a cada novo usuário, tudo usando factories. Importante lembrar que já existe um Factory padrão para usuários ( database/factories/UserFactory.php ). factory(App\User::class, 5) ->create() ->each(function ($user) { $user->products()->saveMany( factory(App\Models\Product::class, 25)->make(['user_id' => null]) ); }); Lembrando que no model User ( app/User.php ) precisa ter o método products, que relaciona o usuário com os produtos (não se preocupe sobre relacionamentos de tabelas, mais adiante vamos detalhar bastante este assunto): public function products() { // Não esquece: use App\Models\Product; return $this->hasMany(Product::class); } Após fazer a alteração rode novamente o comando para criar os novos usuários e vincular 25 produtos a cada um: php artisan db:seed Para evitar erros com valor únicos nas tabelas, você pode deletar as tabelas, recriar novamente e já rodar os seeders, desta forma: php artisan migrate:refresh --seed af://n720 Eloquent Introdução O Eloquent é o nome ORM do Laravel, que fornece um simples e ao mesmo tempo robusta ActiveRecord para manipular banco de dados. Normalmente cada tabela do banco de dados tem seu próprio Model, que é usado para interagir com a tabela, e a partir desse Model é possível consultar os registros, inserir novos registros, deletar e até mesmo alterar os registros. Para explorar o Eloquent ORM do Laravel precisamos primeiramente configurar o acesso ao banco de dados, e o arquivo de configuração de database no Laravel é o config/database.php (assunto já abordado no livro). Criar Models Primeiro passo para explorar o Eloquent do Laravel é definir os Models, as classes (Models) ficam localizadas por default (padrão) no diretório app/ . Todos Models do Eloquent devem herdar da classe Illuminate\Database\Eloquent\Model . Para criar um novo model, podemos usar o comando do artisan make:model NOME_MODEL , nesse exemplo vamos criar o Model Product: php artisan make:model Product Se conferir em app/ criou um nova classe chamada Product, com este conteúdo: namespace App; use Illuminate\Database\Eloquent\Model; class Product extends Model { // } Esse é o conteúdo básico de um Model, mas, o mais importante é notar que a classe Product estende da classe Model, que é a classe que disponibiliza os recursos do Eloquent. Particularmente não gosto de armazenar os Models em app/ , prefiro criar pelo menos uma estrutura app/Models/ para ficar um pouco mais organizado. Felizmente o artisan permite criar as classes de Models em qualquer diretório em app/ , e caso não exista, ele o cria. Portanto, vamos salvar nossas classes de Models em app/Models/ . Primeiro passo, delete o arquivo app/Product.php , acesse o terminal e rode o comando: af://n734 af://n735 af://n740 php artisan make:model Models\\Product Ao rodar o comando make:model passando Models\\ ele vai criar o arquivo em app/Models/Product.php , e também o namespace da classe Product já estará correspondente ao path (caminho) da classe: namespace App\Models; use Illuminate\Database\Eloquent\Model; class Product extends Model { // } É possível criar o Model e já automatizar mais um passo, que no caso é criar o arquivo de migration correspondente: php artisan make:model Models\\Product --migration Ou: php artisan make:model Models\\Product -m A passar a opção --migration ou -m já cria o Model Product em app/Models/Product.php e também cria o arquivo de migration correspondente ao model. Um ponto interessante é que ao criar o arquivo de migration, tanto o nome do arquivo de migration, quanto o nome da tabela ficam no plural do model, como o nosso model se chamam Product, logo a tabela no arquivo de migration será products , e o arquivo terá um nome mais ou menos assim database/migrations/timestamps_create_products_table , com essa estrutura inicial: public function up() { Schema::create('products', function (Blueprint $table) { $table->increments('id'); $table->timestamps(); }); } Padrões af://n764 O sistema de Eloquent do Laravel procura "adivinhar" algumas características das tabelas do banco de dados, e por conta disso tem diversos padrões. Porém, o Laravel não é um framework engessado, ele permite que você altere esses padrões e defina a estrutura das tabelas como preferir, e é exatamente isso que vamos ver a partir de agora. Nomes de Tabelas O Eloquent entende que o nome da tabela que o model representa sempre seja o nome do próprio model no plural. Por exemplo, se tiver um model chamado Product, logo vai entender que o nome da tabela é products. Se o model chama Category, logo o nome da tabela será categories, e assim por diante. Porém, você tem liberdade de customizar, ou seja, definir um outro nome para a tabela. Vamos imaginar que a nossa tabela se chama "produtos", e não "products", como fazer para identificar o nome customizado da tabela no model? Simples, basta criar um atributo $table que recebe o nome da tabela atualizado: protected $table = 'produtos'; Veja o exemplo: namespace App\Models; use Illuminate\Database\Eloquent\Model; class Product extends Model { /** * The table associated with the model. * * @var string */ protected $table = 'produtos'; } Chave Primária Por default a chave primária da tabela é a coluna ID, porém, nada lhe impede de alterar isso. No arquivo de migration que mantém a estrutura da tabela a chave primária édefinida da seguinte forma: $table->increments('id'); Mas, se quiser deixar por exemplo: $table->increments('id_produto'); af://n767 af://n776 Isso é permitido! Porém, quando sai do padrão sugerido, e altera o nome da chave primária precisa especificar no model qual é o nome da coluna, para isso basta criar um atributo chamado $primaryKey , informando o nome da coluna que é a chave primária da tabela: protected $primaryKey = 'id_produto'; Outro detalhe sobre a chave primária é que definimos ela como auto-incremento, ou seja, ele vai definir automaticamente o próximo valor de forma incremental. Porém, caso você quiser desabilitar esse auto- incremento e depois definir manualmente o próximo valor, basta criar um atributo chamado $incrementing no model do tipo boolean, recebendo o valor false para não incrementar: protected $incrementing = false; Por default a chave primária é do tipo integer, mas, caso queira definir a chave primária com algum outro tipo de valor, basta criar um novo atributo no model chamado $keyType recebendo o tipo da coluna primária: protected $keyType = 'string'; Timestamps Por padrão ao criar um arquivo de migration ele já cria o arquivo pré-configurado com: $table->timestamps(); Essa opção vai criar duas colunas adicionais na tabela, sendo elas: created_at e updated_at A coluna created_at salva o timestamps atual quando insere um novo registro (isso o Laravel faz automaticamente). A coluna updated_at salva o timestamps atual quando altera um registro (isso o Laravel faz automaticamente). Porém em alguns casos essas colunas podem ser irrelevantes, e caso você opite por não as definir, vai gerar um erro, porque o Laravel tenta inserir esses valores automaticamente, tanto na coluna created_at e na coluna updated_at. Para desabilitar essas duas colunas precisa criar no model um atributo chamado $timestamps recebendo o valor de false: af://n793 namespace App\Models; use Illuminate\Database\Eloquent\Model; class Product extends Model { /** * Indicates if the model should be timestamped. * * @var bool */ public $timestamps = false; } Porém, em alguns casos você pode optar por simplesmente alterar o nome das colunas, alterando de created_at para data_criacao e de updated_at para data_alteracao. Nesse caso precisa criar no model duas constantes com os valores atualizados dos nomes das colunas: const CREATED_AT = 'data_criacao'; const UPDATED_AT = 'data_alteracao'; Por padrão o formato do timestamps das colunas created_at e updated_at são: 'Y-m-d H:i:s', porém caso queira salvar o timestamps em outro formato, basta criar um atributo chamado $dateFormat no model recebendo o valor desejado: namespace App\Models; use Illuminate\Database\Eloquent\Model; class Product extends Model { /** * The storage format of the model's date columns. * * @var string */ protected $dateFormat = 'd/m/Y H:i:s'; } Models af://n810 Uma vez que criou os models, que estão associados cada um a uma tabela do sistema, já podemos manipular os registros das tabelas a partir dos models. Para manipular o model Product vamos criar um controller, para facilitar o testes. Para criar um novo controller rode esse comando do artisan: php artisan make:controller ProductController Veja que foi criado um arquivo em app/Http/Controllers/ProductController.php , e nessa class ProductController que vamos realizar os testes. Defina um novo método chamado por exemplo tests, porque é nele que inicialmente vamos realizar os testes: public function tests() { } Também precisa definir uma rota para acessar o método tests do controller ProductController, portanto, no arquivo de rotas routes/web.php defina uma nova rota chamada por exemplo tests: Route::get('tests', 'ProductController@test'); No Browser inicie a aplicação na rota tests: http://localhost/tests Listando os registros Para listar os registros da tabela products , podemos fazer dessa forma: public function tests() { // Não esquece de importar o Model Product: use App\Models\Product; $products = Product::all(); } Para debugar o resultado, use o helper (método) dd: public function tests() { $products = Product::all(); dd($products); } http://localhost/tests af://n822 Porém, como estamos apenas testando vamos listar os registros diretamente no controller (isso não é recomendado, faça apenas para testes, o ideal é passar os dados para a view e ela lista) public function tests() { $products = Product::all(); foreach ($products as $product) { echo "{$product->title} <br>"; } } Nos exemplos utilizamos o método all para retornar todos os registros, também podemos usar o método get para retornar todos os registros da tabela, o resultado será o mesmo. Filtros Também é possível aplicar filtros para retornar os registro, nesse exemplo vamos retornar apenas os produtos que estão ativos, para isso podemos combinar o método where: public function tests() { $products = Product::where('active', true)->get(); foreach ($products as $product) { echo "{$product->title} <br>"; } } O método where pode receber até 3 parâmetros: where('coluna', 'condição', 'valor'). Quando informa apenas 2 parâmetros o primeiro é a coluna e o segundo é o valor: where('coluna', 'valor'), nesse caso só o operador assumido é o "=" Como listar apenas os registros inativos? Agora precisamos explorar o método where e passar 3 parâmetros, porque a condição que precisamos usar para filtrar não é mais o "=" e sim o "!=" ou "<>" (diferente). af://n836 public function tests() { $products = Product::where('active', '<>', true)->get(); // ou: Product::where('active', false)->get(); foreach ($products as $product) { echo "{$product->title} <br>"; } } Também é possível combinar várias condições, como por exemplo, exibir apenas os produtos ativos, e os produtos cujo os preços são maiores ou igual a 20: public function tests() { $products = Product::where('active', true) ->where('price', '>=', 20) ->get(); foreach ($products as $product) { echo "{$product->title} <br>"; } } Caso queira analisar a query sql final troque o método get, pelo método toSql e debuge com o método dd: public function tests() { $products = Product::where('active', true) ->where('price', '>=', 20) ->toSql(); dd($products); } Mais detalhes sobre o método where no capitulo Query Builder Um detalhe importante é que, quando usamos o método get ou o método all retorna uma collection (array), que são instâncias de Illuminate\Database\Eloquent\Collection E quando usamos o método first retorna apenas um único registro, e o retorno é um objeto do model correspondente, exemplo: public function tests() { $products = Product::get(); // $products é uma collection (array com 0 ou N registros) $product = Product::first(); // Retorna apenas o primeiro resultado encontrado, logo $product é um objeto do model Product } Inserir Uma das maneiras de inserir um novo registro no database é criar uma nova instância do model, setar os atributos, e usar o método save para inserir: namespace App\Http\Controllers; use App\Models\Product; use Illuminate\Http\Request; use App\Http\Controllers\Controller; class ProductController extends Controller { /** * Create a new product instance. * * @param Request $request * @return Response */ public function store(Request $request) { $product = new Product; $product->name = 'Produto x'; $product->description = 'Descrição do produto x'; $product->save(); // Cria novo produto // Objetodo novo produto: dd($product); } } Veja que neste exemplo inserimos manualmente todas as propriedades, que são correspondentes aos nomes das colunas da tabela. Os valores para as colunas created_at e updated_at são inseridos automaticamente pelo Laravel. af://n858 Embora seja algo muito funcional essa abordagem, não é produtivo, isso porque precisamos informar manualmente o valor para cada coluna da nossa tabela que desejamos inserir algum valor. E se essa tabela conter 100 colunas (algum possível e comum)? Neste método de desenvolvimento é extremamente improdutivo. Para resolver esse cenário podemos usar o método create e passar um array como parâmetro com todos os valores que desejamos inserir, veja o exemplo: public function store(Request $request) { $product = Product::create([ 'name' => 'Produto x', 'description' => 'Descrição do produto x', ]); // Objeto do novo produto: dd($product); } Observe que o método create pode tornar o nosso trabalho mais produtivo, justamente por receber um array com os valores que é para ser inserido, note também a coerência das chaves do array, devem ser exatamente iguais aos nomes das colunas da tabela. A vantagem deste formato é que podemos explorar o objeto de Request para recuperar todos os parâmetros da requisição http (que podem ser valores que vem de um formulário) e tornar esse exemplo ainda mais simples: $product = Product::create($request->all()); O método all de Request retorna todos os parâmetros da requisição http, ou seja, se essa requisição vier de um formulário automaticamente recupera os valores de todos os campos. Mass Assignment Quando passamos para o método create ou para o método update $request->all() corremos o risco do usuário passar parâmetros inesperados através da requisição HTTP, e estes valores podem afetar diretamente os valores da tabela. Pense por exemplo, que na tabela users exista uma coluna chamada por exemplo is_admin , caso o usuário envie intencionalmente is_admin com o valor de true (1) automaticamente ele se torna um admin, o que neste caso coloca em risco o sistema, porque esse usuário passa a ter privilégios administrativos dentro da aplicação. Porém, o Laravel por padrão possui mecanismos que protege contra essa vulnerabilidade mass-assignment, ao passar um array com os valores que deseja inserir ou editar, automaticamente o Laravel gera um exception (um erro), justamente alertando que precisa especificar qual ou quais valores podem ser inseridos desta forma. Para resolver este caso precisamos acessar o model correspondente e criar um atributo chamado $fillable ou $guarded. af://n870 O atributo $fillable é o mais comum, ele recebe um array com todos as colunas que podem receber valores de forma dinâmica, no caso do último exemplo, no model User não incluímos neste array a coluna is_admin . Esse atributo indica a lista branca. O atributo $guarded faz o papel contrário, ele também recebe um array, porém, com as colunas que não podem receber o valor diretamente. Esse atributo indica a lista negra. Para exemplificar, no model Product ( app/Models/Product.php ) vamos criar o atributo $fillable especificando quais colunas podem receber valores dinamicamente: namespace App\Models; use Illuminate\Database\Eloquent\Model; class Product extends Model { /** * The attributes that are mass assignable. * * @var array */ protected $fillable = ['name', 'description']; // [...] } Neste exemplo limitamos que apenas as colunas name e description podem receber valores dinâmicos através do método create ou update . Se o objetivo é indicar quais colunas NÃO devem receber um valor quando passa um array nos métodos create ou update , deve utilizar o atributo $guarded, neste exemplo vamos restringir que não inseria valor algum na coluna is_admin : /** * The attributes that aren't mass assignable. * * @var array */ protected $guarded = ['is_admin']; Mesmo que passe um array com o valor para is_admin não será enviado para o banco de dados, porque restringimos isso através do atributo $guarded . Outra alternativa é usar o método fill para popular um array com os atributos: $product = new Product; $product->fill($request->all()); $product->save(); // Cria novo produto Editar O método save pode ser usado tanto para inserir um novo registro a partir de um objeto do model, e também pode ser usado para editar um objeto do model. Primeiramente, para atualizar um model recuperamos o registro, definimos todos os atributos que desejamos atualizar, e novamente usamos o método save , porém dessa vez para atualizar. Ao atualizar algum registro automaticamente a coluna de timestemps updated_at será atualizada. Exemplo: $product = Product::where('id', '=', $id)->first(); // ou: Product::find(1); $product->name = 'Novo Nome Para o produto id:1'; $product->save(); Neste exemplo atualizamos apenas o valor para a coluna name , porém qualquer outra informação poderia ser editada. Outra alternativa para editar um registro de forma mais produtiva é usando o método update , assim como o método create também podemos passar um array com todos os valores a serem atualizados. Mas lembre- se, a coerência com as chaves do array com o nome das colunas da tabela. $products = Product::where('id', '=', $id) ->update([ 'name' => 'Novo Nome Para o produto id:1', ]); Neste exemplo todos os produtos cujo a coluna id seja igual ao valor da variável $id serão atualizados a coluna name para o valor indicado. Outra abordagem com o mesmo seria: $product = Product::where('id', '=', $id)->first(); // ou: Product::find(1); $product->update([ 'name' => 'Novo Nome Para o produto id:1', ]); Um exemplo mais real, suponha que a tabela products possua uma coluna chamada active (booleana), que indica se o produto está ativo, ou não. Neste exemplo, vamos ativar todos os produtos que estão desativados: $products = Product::where('active', false) ->update([ 'active' => true, ]); af://n887 Deletar Claro, além de buscar os registros, inserir novos, editar, não pode faltar a opção de deletar, veja como: // Recupera o produto pelo ID $product = Product::where('id', $id)->first(); // Ou simplesmente: Product::find($id); // Deleta o produto $product->delete(); Filtrar e excluir Também é possível deletar em massa, aplicando um filtro ( where ), neste exemplo vamos deletar todos os produtos inativos: // Deletando todos os produtos inativos Product::where('active', false)->delete(); Excluir pela chave primária Outra alternativa até mais simples para deletar um ou mais registros é usando o método destroy , esse método recebe como argumento o valor da chave que é para remover o registro ( id ). // Deletando o produto id=1 Product::destroy(1); // Deletando os produtos id=1,2,3 Product::destroy(1, 2, 3); // Deletando os produtos id=1,2,3 Product::destroy([1, 2, 3]); // Deletando todos os produtos inativos $products = Product::where('active', false)->get(); Product::destroy($products); af://n903 af://n908 af://n913 Soft Deleting Outro recurso interessante do Laravel e que se mostra muito útil em diversos cenários é o Soft Deleting, este recurso permite "deletar" o registro sem excluir. Como assim? É possível criar um tabela com uma coluna "deleted_at", essa coluna é do tipo date (data). O Eloquent do Laravel por padrão seleciona apenas os registros que possuem a coluna "deleted_at" não preenchidos preenchidos, ou seja, com o valor de null. Quando está utilizando o recurso de Soft Deleting ao deletar o registro, o mesmo não é apagado da tabela, apenas o campo deleted_at é preenchido com as informações de timestamps. E quando consulta o registro, por padrão só retorna os registros com a coluna deleted_at está igual anull, ou seja, registros que não foram "deletados". Isso é interessante quando se tem informações valiosas no banco de dados, porque não é interessante neste caso que estes registros sejam apagados, como por exemplo, registros de usuários. Não é interessante excluir definitivamente um registro de usuário no sistema. Para criar a coluna deleted_at na tabela, no arquivo de migration da tabela correspondente basta adicionar: $table->softDeletes(); Essa opção cria a coluna deleted_at na tabela. Utilizando o Recurso de Soft Deleting Para utilizar é muito simples, basta utilizar a Trait SoftDeletes no Model correspondente, apenas isso. Veja um exemplo prático: namespace App\Models; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; class Product extends Model { use SoftDeletes; /** * Opcional, informar a coluna deleted_at como um Mutator de data * af://n922 af://n934 * @var array */ protected $dates = ['deleted_at']; } Agora ao selecionar os registros utilizando o model Product irá retornar apenas os registros que não foram apagados, ou seja, os registros cujo o valor da coluna deleted_at é igual null: #controller public function index(Product $product) { $products = $product->get(); dd($products); } Para analisar a query final e observar o filtro na coluna deleted_at , utilize o método toSql : $products = $product->toSql(); dd($products); // Resultado: select * from products where deleted_at=null Incluindo Registros Deletados Uma alternativa possível é recuperar todos os registros, incluindo os que foram deletados com Soft Deleted , para isso usamos o método withTrashed : // Ex1: $products = Product::withTrashed()->get(); // Query: select * from products; // Ex2: $products = Product::where('active', true)->withTrashed()->get(); No capitulo sobre relacionamentos de tabelas será abordado isso com mais detalhes, porém, é importante saber que é possível aplicar este mesmo filtro para retornar os registros relacionados que foram deletados também: $product = Product::find(1); $comments = $product->comments()->withTrashed()->get(); af://n944 Recuperando Apenas os Deletados Também é possível trabalhar apenas com os registros que foram deletados com Soft Deleted , para isso usamos o método onlyTrashed : // Ex1: $products = Product::onlyTrashed()->get(); // Query: select * from products where deleted_at<>null; // Ex2: $products = Product::where('active', true)->onlyTrashed()->get(); Também é possível retornar apenas os registros relacionados que foram deletados: $product = Product::where('id', 1)->first(); $comments = $product->comments()->onlyTrashed()->get(); Restaurando Como obviamente o registro não foi efetivamente deletado, podemos restaurar quando necessário, neste exemplo vamos restaurar os produtos, para isso usamos o método restore : // Ex1 (restaurando todos): Product::withTrashed()->restore(); // Ex2 (restaurando apenas os ativos): Product::where('active', true)->withTrashed()->restore(); Também é possível restaurar os registros relacionados, no exemplo vamos restaurar todos os comentários do produto 1: $product = Product::where('id', 1)->first(); $product->comments()->restore(); Deletar Permanentemente af://n952 af://n960 af://n968 Em alguns casos pode ser necessário deletar um registro permanentemente, para isso podemos usar o método forceDelete : $product = Product::where('id', 1)->first(); $product->forceDelete(); // Tudo na mesma linha: Product::where('id', 1)->first()->forceDelete(); Também podemos deletar permanentemente todos os registros relacionados, neste exemplo vamos deletar todos os comentários do produto 1: $product = Product::where('id', 1)->first(); $product->comments()->forceDelete(); Outras Opções firstOrCreate O método firstOrCreate recupera o registro caso exista, ou, cria um novo registro. Vamos ao exemplo: $product = Product::firstOrCreate([ 'name' => 'Produto Nome', 'description' => 'Descrição do Produto', ]); dd($product); Neste exemplo, primeiramente verifica se existe algum produto cujo o valor da coluna name seja igual a "Produto Nome" e o valor para a coluna description seja igual a "Descrição do Produto", se encontrar o registro com estes valores devolve o objeto do model de Product para a variável $product, caso contrário, cria um novo produto com estes valores e devolve o objeto de Product. A vantagem dessa abordagem é que garante que não haja registros com valores idênticos duplicados no banco de dados. Faça o teste, tente inserir diversas vezes o mesmo registro com essa implementação (atualize a página diversas vezes), no final, terá apenas um único registro. firstOrNew af://n977 af://n978 af://n985 O método firstOrNew trabalha muito semelhante ao firstOrCreate , porque não insere um registro duplicado, porque verifica se o registro já existe na tabela. Porém, precisa especificar que é para inserir, isso porque quando não encontra o registro ele não insere imediatamente, na realidade o método firstOrNew retorna um novo objeto do model, e para inserir precisa chamar o método save , veja o exemplo: // Verifica se existe um produto com esse nome e descrição: $product = Product::firstOrNew([ 'name' => 'Produto Nome', 'description' => 'Descrição do Produto', ]); // Se existir retorna o objeto com os dados do produto, caso contrário retorna uma nova instância de Product. // Insere o registro, caso não exista ainda $product->save(); dd($product); updateOrCreate O método updateOrCreate é muito útil e interessante, porque ele pode inserir ou simplesmente atualizar um registro. Esse método recebe dois parâmetros, o primeiro são as condições, e o segundo, o que é para atualizar. Exemplo: $product = Product::updateOrCreate( [ 'name' => 'Produto Nome', 'description' => 'Descrição do Produto', ], ['description' => 'Nova descrição'] ); dd($product); Neste exemplo, primeiramente verifica se existe algum produto cujo o valor da coluna name seja igual a "Produto Nome" e o valor para a coluna description seja igual a "Descrição do Produto", se encontrar o registro atualiza o valor da coluna description para "Nova descrição" (porque é o segundo parâmetro do método que define o que será atualizado). Comparando Models Em alguns casos pode que eventualmente seja necessário comparar se os models são iguais. O método is pode ser usado para comparar, veja: af://n990 af://n996 $user = User::find(1); if ($product->is($user)) { // } Eloquent Relacionamentos de Tabelas Bancos de dados relacionais permitem relacionar registros em diferentes tabelas. Os relacionamentos possíveis são: One to One (Um para Um) One to Many (Um para Muitos) Many to One (Muitos para Um) Many to Many (Muitos para Muitos) O Eloquent do Laravel permite trabalhar com todos os relacionamentos citados acima, de forma muito fácil e simples, e ainda dispõe de mais algumas artimanhas para ajudar a relacionar registros seguindo outras opções: Has Many Through Polymorphic Relations (Relações Polimórficas) Many To Many Polymorphic Relations (Muitos para Muitos - Relações Polimórficas) af://n1002 https://www.youtube.com/watch?v=Ofi18M5kLgY https://www.youtube.com/watch?v=1P7aPUh5WLQ https://laravel.com/docs/5.7/eloquent-relationships#polymorphic-relationships Eloquent Relationships One to One Esse é o relacionamento mais básico. Pense em um sistema onde o usuário pode ter informações por exemplo de latitude e longitude. Essas suas informações podem até estar na tabela de users junto com as demais colunas, porém fica mais didático ter uma outra tabela simplesmente para quebrar essas informações e tornar a tabela de users mais simples possível. Nesse exemplo vamos criar uma tabela chamada locations, para amazenar
Compartilhar