Usando Illuminate Database com Eloquent em Seu App PHP sem Laravel


by 
Difficulty:IntermediateLength:LongLanguages:
English
العربية/عربي
Deutsch
Español
Bahasa Indonesia
Melayu
Português
Pусский
Türkçe
Tiếng Việt

Portuguese (Português) translation by Erick Patrick (you can also view the original English article)

Illuminte é o motor da base de dados do Laravel sem o Laravel. Ele vem junto do Eloquent ORM no Laravel. Se gostamos de criar apps em PHP com ORMs e não queremos usar Laravel, esse tutorial vai ajudar.

Nele, criaremos o backend de um app de perguntas e respostas com PHP, Illuminate Database e o Eloquent ORM.

  1. PHP: 5.5+
  2. MYSQL
  3. Composer

Nosso app realiza dez tarefas:

  • Adicionar um usuário
  • Adicionar uma pergunta
  • Adicionar resposta de uma pergunta
  • Votar favoravelmente uma resposta
  • Obter uma pergunta com respostas
  • Obter todas as perguntas e usuários que as perguntaram
  • Obter perguntas específicas, respostas e votos favoráveis
  • Contar perguntas de um usuário em particular
  • Atualizar resposta de um usuário
  • Remover uma pergunta

Primeiro, criaremos a pasta e estrutura do projeto.

Na pasta principal do projeto, criaremos a pasta app e dentro dela, criaremos duas outras: models e controllers. Na figura abaixo, a pasta principal é chamada de eloquent. Podemos alterá-lo para o nome que preferirmos.

Our project organization

Depois, criemos index.php na pasta principal, no mesmo nível da pasta app.

Usaremos git, então criemos o arquivo .gitignore. Esse passo é opcional.

Depois, instalemos as dependências necessárias para o projeto funcionar. Na raiz do projeto, criaremos composer.json e colaremos o código abaixo nele.

1
2
3
4
5
6
{
 “name”: “illuminate-example/eloquent”,
 “description”: “Implementation of Database Queries with illuminate and Eloquent”,
 “type”: “project”,
 “require”: {}
}

Para instalar a base de dados Illuminate, adicionamos isso ao composer.json:
“illuminate/database”: “5.1.8”,.

Depois, adicionamos o auto-carregamento PSR-4 dos Modelos e Controladores:

1
2
3
4
5
“autoload”: {
 “psr-4”: {
 “Controllers\\”: “app/controllers/”,
 “Models\\”: “app/models/” }
 }

Agora, o composer.json deve parecer com isso:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
{
 “name”: “illuminate-example/eloquent”,
 “description”: “Implementation of Database Queries with illuminate and Eloquent”,
 “type”: “project”,
 “require”: {
 “illuminate/database”: “5.1.8”},
 “autoload”:
    {“psr-4”:
        { “Controllers\\”: “app/controllers/”,
            “Models\\”: “app/models/"
            
                 }
    }
}

Executaremos esses dois comandos na mesma pasta do composer.json:

1
2
composer install
composer dump-autoload -o

Eles gerarão uma pasta vendor que adicionaremos ao gitignore (também é opcional).

Criemos a configuração com as credenciais da base de dados.

Na pasta raiz, criemos config.php e definamos os detalhes do banco em config.php. Notemos que os valores devem ser substituídos pelos detalhes reais de conexão.

1
2
3
4
5
6
7
<?php
defined(“DBDRIVER”)or define(‘DBDRIVER’,’mysql’);
defined(“DBHOST”)or define(‘DBHOST’,’localhost’);
defined(“DBNAME”)or define(‘DBNAME’,’eloquent-app’);
defined(“DBUSER”)or define(‘DBUSER’,’root’);
defined(“DBPASS”)or define(‘DBPASS’,’pass’);

Depis, criaremos o esquema do app.

Algo a notar antes de criarmos os esquemas das tabelas na base de dados é que podemos adicionar marcas de hora neles.

O Eloquent ORM espera por duas colunas de marcas de hora se habilitarmos a operação de marca de hora em um modelo/tabela. São as colunas created_at e updated_at. Se habilitarmos essa funcionalidade, o Eloquente atualizará esses campos automaticamente com o horário de criação ou atualização.

Há uma terceira coluna, deleted_at. Esse campo de marca de hora funciona diferente. Eloquente pode “desabilitar” um registro, usando a coluna deleted_at para determinar quando ele foi desabilitado. Se removermos um registro com a função ‘delete’ do eloquente e usarmos essa funcionalidade, a coluna é atualizada com o horário da remoção. Então eles podem ser obtidos a qualquer hora.

Nesse app, lançaremos mão das marcas de hora, então usaremos todo os três campos na criação do esquema.

Criemos as tabelas com os comandos MySQL a seguir:

1
2
3
4
5
6
7
8
9
CREATE TABLE `questions` (
 `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
 `question` tinytext,
 `user_id` int(11) DEFAULT NULL,
 `created_at` timestamp NULL DEFAULT NULL,
 `updated_at` timestamp NULL DEFAULT NULL,
 `deleted_at` timestamp NULL DEFAULT NULL,
 PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Advertisement
01
02
03
04
05
06
07
08
09
10
CREATE TABLE `answers` (
 `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
 `answer` tinytext,
 `user_id` int(11) DEFAULT NULL,
 `question_id` int(11) DEFAULT NULL,
 `created_at` timestamp NULL DEFAULT NULL,
 `updated_at` timestamp NULL DEFAULT NULL,
 `deleted_at` timestamp NULL DEFAULT NULL,
 PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
1
2
3
4
5
6
7
8
9
CREATE TABLE `upvotes` (
 `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
 `answer_id` int(11) DEFAULT NULL,
 `user_id` int(11) DEFAULT NULL,
 `created_at` timestamp NULL DEFAULT NULL,
 `updated_at` timestamp NULL DEFAULT NULL,
 `deleted_at` timestamp NULL DEFAULT NULL,
 PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
01
02
03
04
05
06
07
08
09
10
CREATE TABLE `users` (
 `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
 `username` varchar(100) DEFAULT NULL,
 `email` varchar(200) DEFAULT NULL,
 `password` varchar(200) DEFAULT NULL,
 `created_at` timestamp NULL DEFAULT NULL,
 `updated_at` timestamp NULL DEFAULT NULL,
 `deleted_at` timestamp NULL DEFAULT NULL,
 PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Continuaremos criando os arquivos dos modelos e controladores para nossas tabelas nos seguintes locais:

  • project_folder/app/models/question.php
  • project_folder/app/models/answer.php
  • project_folder/app/models/upvote.php
  • project_folder/app/models/user.php
  • project_folder/app/models/database.php
  • project_folder/app/controllers/questions.php
  • project_folder/app/controllers/answers.php
  • project_folder/app/controllers/upvotes.php
  • project_folder/app/controllers/users.php

Abramos models/database.php em um editor.

Primeiro criemos a Capsula:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php
namespace Models;
use Illuminate\Database\Capsule\Manager as Capsule;
class Database {
    function __construct() {
    $capsule = new Capsule;
    $capsule->addConnection([
     ‘driver’ => DBDRIVER,
     ‘host’ => DBHOST,
     ‘database’ => DBNAME,
     ‘username’ => DBUSER,
     ‘password’ => DBPASS,
     ‘charset’ => ‘utf8’,
     ‘collation’ => ‘utf8_unicode_ci’,
     ‘prefix’ => ‘’,
    ]);
    // Setup the Eloquent ORM…
    $capsule->bootEloquent();
}
}

No arquivo acima, inicializamos e configuramos a capsula com as constantes definidas em config.php e iniciamos o Eloquente.

O próximo passo é criar o script de inicialização. É o arquivo onde tudo tem de executar antes do app rodar.

Criamos esse arquivo em project_folder/start.php e então requeremos o arquivo auto-carregador do Composer:

require ‘vendor/autoload.php’;

Depois, requeremos config.php e obtemos as credenciais definidas: require 'config.php';.

Então inicializamos a classe da base de dados.

1
2
3
4
5
6
<?php
use Models\Database;
//Boot Database Connection
new Database();

Nosso start.php deve parecer com isso:

1
2
3
4
5
6
7
<?php
require ‘config.php’;
require ‘vendor/autoload.php’;
use Models\Database;
//Initialize Illuminate Database Connection
new Database();
?>

Incluamos o start.php em index.php já que este será o principal.

Nosso index.php parece com isso:

1
2
3
<?php
require ‘start.php’;
?>

Depois, começamos a trabalhar nos controladores e modelos. Em project_folder/app/models/question.php adicionamos:

01
02
03
04
05
06
07
08
09
10
11
12
13
<?php
namespace Models;
use \Illuminate\Database\Eloquent\Model;
class Question extends Model {
    
    protected $table = ‘questions’;
    
}
?>

Então em project_folder/app/controllers/questions.php:

1
2
3
4
5
6
7
8
<?php
namespace Controllers;
class Questions{
    
}
?>

Em project_folder/app/controllers/answers.php, fazemos o mesmo:

1
2
3
4
5
6
7
<?php
namespace Controllers;
class Answers{
    
}
?>

No modelo do usuário (project_folder/app/models/user.php), adicionamos o código baixo para definir nosso espaço de nome, estendemos o Modelo Eloquent e definimos o nome da tabela (protected $table) e quais campos da tabela são preenchíveis em criação em massa (protected $fillable).

1
2
3
4
5
6
7
8
9
<?php
namespace Models;
use \Illuminate\Database\Eloquent\Model;
class User extends Model {
    protected $table = ‘users’;
    protected $fillable = [‘username’,’email’,’pass’];
}
?>

No controlador dos usuários (project_folder/app/controllers/user.php), definimos o nome de espaço e classe, como de costume.

1
2
3
4
5
6
7
<?php
namespace Controllers;
class Users{
    
}
?>

Para criamos o usuário, no controlador do usuário importaremos o modelo do usuário, use Models\User;, e adicionaremos uma função para criar um usuário.

1
2
3
4
5
6
<?php
    public static function create_user($username, $email, $password){
        $user = User::create(['username'=>$username,'email'=>$email,'password'=>$password]);
        return $user;
    }

Nosso controlador de usuário parece com isso agora.

01
02
03
04
05
06
07
08
09
10
11
12
13
<?php
namespace Controllers;
use Models\User;
class Users {
    
    public static function create_user($username, $email, $password){
        $user = User::create(['username'=>$username,'email'=>$email,'password'=>$password]);
        return $user;
    }
}
?>

Então, no index.php, adicionamos essa linhas e executamos o app para criar um novo usuário.

1
2
3
4
5
6
<?php
use Controllers\Users;
// Import user controller
$user = Users::create_user(“user1”,”user1@example.com”,”user1_pass”);

Para adicionar uma pergunta, importamos o modelo Question no controlador das questões e criamos a função create_function:

use Models\Question;

Então:

1
2
3
4
5
6
7
<?php
public static function create_question($question,$user_id){
    $question = Question::create(['question'=>$question,'user_id'=>$user_id]);
    return $question;
}

Usamos a criação em massa do Eloquent para criar registros, mas, antes de funcionar, precisamos permitir que os campos sejam preenchíveis, porque os modelos do Eloquent protegem contra criação em massa por padrão.

Então, vamos ao modelo question e adicionamos a propriedade protected $fillable à classe.

protected $fillable = ['questions', 'user_id'];

Para executar isso, importemos o controlador de perguntas no index.php e invoquemos create_question estaticamente:

use Controllers\Question;

Para criar uma pergunta com uma pergunta e id de usuário como parâmetros:

$question = Questions::create_question('Have you ever met your doppelganger?', 1);

Isso retorna um objeto modelo se bem sucedido.

Agora executaremos index.php com valores diferentes para adicionar mais perguntas à base de dados.

No modelo resposta, repetimos os passos que fizemos para pergunta e usuários, adicionando o código abaixo:

01
02
03
04
05
06
07
08
09
10
11
<?php
namespace Models;
use \Illuminate\Database\Eloquent\Model;
class Answer extends Model {
    
    protected $table = ‘answers’;
    protected $fillable = [‘answer’,’user_id’,’question_id’];
    
}
?>

Então no controlador answers, colocamos essas linhas:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
<?php
namespace Controllers;
use Models\Answer;
class Answers {
    public static function add_answer($answer,$question_id,$user_id){
        $answer = Answer::create(['answer'=>$answer,'question_id'=>$question_id,'user_id'=>$user_id]);return $answer;
    }
}
?>

Então em index.php, criamos uma resposta para a pergunta de id 1, com usuário id 2. Não esqueçamos de importar o controlador answers no index.php.

1
2
3
4
5
<?php
use Controllers\Answers;
    $answers = Answers::add_answer(“This is an answer”,1,2);

Para prevenir múltiplos registros, comentemos todas as outras chamadas em index.php antes de executa uma nova.

São, basicamente, os mesmos passos que já usamos.

Então, colocaremos isso no modelo Upvote em project_folder/app/models/upvote.php.

01
02
03
04
05
06
07
08
09
10
11
12
13
<?php
namespace Models;
use \Illuminate\Database\Eloquent\Model;
class Upvote extends Model {
    protected $table = 'upvotes';
    protected $fillable = ['answer_id','user_id'];
     
}
 ?>

Então, no controlador answers, importamos o modelo Upvote.

use Models\Upvote;

Então criamos a função upvote_answer.

1
2
3
4
5
6
<?php
    public static function upvote_answer($answer_id,$user_id){
        $upvote = Upvote::create(['answer_id'=>$answer_id,'user_id'=>$user_id]);
        return $upvote;
    }

Em index.php, invocamos a função com um id de usuário falso e respota de id 1.

$upvote = Answers::upvote_answer(1,14);

Para tarefas como essa, usamos as relações do Eloquent.

Tipos de relacionamento incluem: um a um, um para muitos, muitos para muitos, etc.

Ao usar esses relacionamentos, o Eloquent assume que há a chave estrangeira no formato modelname_id nos modelos. Para essa tarefa, o relacionamento é um-para-muitos, porque uma pergunta pode ter várias respostas.

Primeiro, definamos esse relacionamento adicionando essa função ao modelo question.

1
2
3
4
5
6
<?php
public function answers()
{
    return $this->hasMany('\Models\Answer');
}

Então no controlador questions, escrevemos a função de obter as perguntas com respostas.

1
2
3
4
5
6
7
<?php
public static function get_questions_with_answers(){
 
    $questions = Question::with('answers')->get()->toArray();
    return $questions;
}

Isso retorna as perguntas com suas respostas.

Em index.php, comentamos as outras chamadas e executamos:

$all = Questions::get_questions_with_answers();

Podemos usar var_dump ou print_r em com $all para ver o resultado.

Essa é uma relação um-para-um porque uma pergunta tem um usuário, então adicionemos isso ao modelo question.

1
2
3
4
5
6
<?php
public function user()
{
    return $this->belongsTo(‘\Models\User’);
}

Então criamos uma função no controlador questions e usemos a função with no modelo question.

1
2
3
4
5
6
7
<?php
public static function get_questions_with_users(){
    $questions = Question::with('user')->get()->toArray();
    return $questions;
}

Em index.php, comentemos todo o resto e executemos:

$all_with_users = Questions::get_questions_with_users();

Primeiro, temos a relação entre perguntas e votos. Uma pergunta pode ter vários votos, então o relacionamento é um-para-muitos.

Então, adicionamos a função abaixo no modelo answer:

1
2
3
4
5
6
<?php
public function upvotes()
{
    return $this->hasMany('\Models\Upvote');
}

Então no controlador questions, criamos essa função:

1
2
3
4
5
6
7
<?php
public static function get_question_answers_upvotes($question_id){
    $questions = Question::find($question_id)->answers()->with('upvotes')->get()->toArray();
    return $questions;
}

Como antes, comentamos todas as outras chamadas e executamos essa:

$one_questions = Questions::get_question_answers_upvotes(1);

Podemos imprimir $one_question para ver os resultados.

Primeiro, importamos o modelo question no controlador users:

use Models\Questions;

Então criamos essa função:

1
2
3
4
5
6
7
<?php
public static function question_count($user_id){
    $count = Question::where('user_id',$user_id)->count();
    return $count;
}

Em index.php, comentamos as outras chamadas e adicionamos:

$user_question_count = Users::question_count(1);

Isso retorna um inteiro que é o número de perguntas que foram adicionas pelo usuário de id 1.

Podemos imprimir $user_question_count e executar index.php para ver os resultados.

O conceito de atualização com Eloquent ORM é bem simples. Primeiro buscamos um registros, modificamos e salvamos.

Agora, no controlador answers, adicionamos essa função:

1
2
3
4
5
6
7
8
<?php
public static function update_answer($answer_id,$new_answer){
    $answer = Answer::find($answer_id);
    $answer->answer = $new_answer;
    $updated = $answer->save();
    return $updated;
}

Em index.php, comentamos as outras chamadas e atualizamos a resposta com id 1, dessa forma:

$update_answer = Answers::update_answer(1, "This is an updated answer");

Isso retorna um booleano—true—se for bem sucedido.

Na tarefa final, implementaremos o desabilitar do Eloquent.

Primeiro, dizemos ao modelo question para usar SoftDeletes importando-o e então usando a trait SoftDeletes na classe.

use Illuminate\Database\Eloquent\SoftDeletes;

Então, depois da declaração da classe, adicionamos isso:

use SoftDeletes;

Então adicionamos deleted_at à propriedade protected $dates do modelo. Esses são passos obrigatórios.

protected $dates = ['deleted_at'];

Nosso modelo question parece com isso agora:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?php
namespace Models;
use \Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Question extends Model {
use SoftDeletes;
    protected $table = 'questions';
    protected $fillable = ['question','user_id'];
    public function answers()
    {
        return $this->hasMany('\Models\Answer');
    }
    
    
    public function user()
    {
        return $this->belongsTo('\Models\User');
    }
 }
 ?>

Então criemos a função delete_question no controlador questions.

1
2
3
4
5
6
7
8
9
<?php
public static function delete_question($question_id){
    $question = Question::find($question_id);
    $deleted = $question->delete();
    return $deleted;
}

Executemos index.php:

$delete = Questions::delete_question(1);

Parabéns! Criamos um backend funcional com Illuminate e Eloquent. E não tivemos de escrever muito código para obter tudo isso.

O código desse tutorial pode ser visto no GitHub.

Illuminate também vem com um construtor de consultas que podemos usar para consultas ainda mais complexas e é algo que devemos experimentar em nossos apps.

A única coisa faltando no Illuminate Database puro é a migração, que é um recurso muito legal do Laravel e do Lumen, o microframework do Laravel. Devemos considerar o uso de ambos nos apps para lançar mão dos úteis recursos que vem com eles.

Encontramos mais sobre Eloquent na Documentação Oficial do Eloquente.

Advertisement

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair /  Alterar )

Foto do Google

Você está comentando utilizando sua conta Google. Sair /  Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair /  Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair /  Alterar )

Conectando a %s