AndersonArruda

Artigos de tecnologia ao alcance de um clique!


Laravel - Entendendo Model
laravel model o que é model mvc event laravel event laravel scope scope

Laravel - Entendendo Model

16/11/2023 21:47

Uma das coisas mais legais do Laravel são seus Models e sua capacidade incrível de várias possibilidades, filtros pré-definidos e outros conceitos para aprimorar aquilo que o Model deveria compreender.


Antes de continuarmos esse assuntos vamos lembrar o que significa MVC?


MVC - Model View Controller


Model: O tema do nosso assunto de hoje, este representa os dados do aplicativo, sua estrutura, lógica e comportamento. Trata de regras de negócio, realiza operações em database e responde a consulta sobre seus dados, em suma encapsula a lógica de negócio e o acesso aos dados.


View: Interface do usuário UI.


Controller: Controlador ele intermedia a transição entre a view e os model. Recebe solicitações do usuário por meio de interface, processa essas solicitações, "geralmente com base na lógica de negócios definidas pelo modelo" e atualiza o model. Além disso atualiza as views com novos dados após a atualização do modelo.


Laravel - Model Scope


Existem 3 possibilidade de scope no Laravel, vamos falar mais do local scope pois utilizaremos mais, mas vou elencar os outros scope pra você ficar ciente da existência deles e como eles funcionam.


Global Scope

Global Scope é um scope que pode ser compartilhado entre vários Models diferentes, por exemplo você tem uma regra temporal e faz uma comparação com created_at em vários models, pode criar um scope global. Além de que ele sempre é utilizado pelo model.


Para criá-lo você deve gerar um arquivo do tipo scope rodando o comando:


php artisan make:scope TemporalScope


Nele é necessário ter o método apply onde aplicará a regra do scope.


Para aplicar esse scope em um Model existente você deve sobreescrever o método booted e invocar o método addGlobalScope.

protected static function booted(): void
{
  static::addGlobalScope(new TemporalScope);
}

Para entender melhor sobre global scope, veja o link abaixo com a documentação oficial, não é o ênfase do nosso tema de hoje.


https://laravel.com/docs/10.x/eloquent#query-scopes


Anonymous Global Scope

Equivalente ao Global Scope porém utilizando-se dos conceitos anônimos, declaração de função sem nome por exemplo.


protected static function booted(): void
{
    static::addGlobalScope('ancient', function (Builder $builder) {
        $builder->where('created_at', '<', now()->subYears(2000));
    });
}


Removendo global scope da consulta

Bem simples basta utilizar o método withoutGlobalScope e o nome do global scope.

Exemplo:


User::withoutGlobalScope(TemporalScope::class)->get();


Local Scope

Permite a definição de um conjunto de regras comunitárias para a query que você facilmanete poderá reutilizar no seu código.


Scope sempre deve retornar void.


Vou explicar o porque vou utilizar e como vou utilizar usando meu projeto SBBlog de exemplo, caso ainda não conheça e queira, é um código aberto de blog que mantenho para qualquer um utilizar e construir seu próprio blog.

https://github.com/andmarruda/sbblog


Retomando o raciocínio, o Sbblog por definição vem com um usuário criado que permite você logar, porém ele não deve ser um usuário que deva ficar ativo pois apresentária um enorme risco de segurança ao sistema, uma enorme vulnerabilidade, então o sistema verifica se o usuário logado é o primeiro usuário, se for ele te redireciona para a rota de criação de um novo usuário e te prende nela, forçando você criar um novo usuário, com isso automáticamente ele desativa o primeiro usuário e após alguns segundos te desloga do sistema, forçando você logar com o seu usuário definitivo, inclusive essa parte de desativação estará constando aqui em nosso artigo, pois estarei explicando sobre eventos em Models no Laravel.


No model eu tenho uma constante que segue:

const FIRST_USER_EMAIL = 'admin@admin.com';


Onde o email checa se o usuário é o usuário pré-definido pelo sistema.

O scope vai ficar da seguinte forma:


public function scopeFirstUserLogged(Builder $query) : void
{
    $query->where('email', self::FIRST_USER_EMAIL)
        ->where('id', auth()->check() ? auth()->user()->id : -1);
}


Esse método recebe por definição o Builder do laravel Illuminate\Database\Eloquent\Builder , mas você notará que nem precisará se preocupar com isso, pois isso acontece internamente pelo Laravel, e o legal que esse scope serve também para métodos que retornam hasMany, belongsTo, hasOne e por ae vai...


Mas e como eu utilizo isso?

Extremamente simples no meu caso basta fazer a pergunta certa ao sistema...


User::firstUserLogged()->count() > 0 //0 isn`t 1 yes is him


Aqui já expliqueio o conceito, pra que serve e como utilizar, seguindo esse raciocínio passarei pra falar sobre eventos em Models, pois assim que criar um novo usuário eu quero desativar o usuário inicial do sistema, lembrando que nesse caso ele deve servir exclusivamente para gerar o ambiente para criação de um usuário.


Eventos

Vamos criar um evento para quando inserir um usuário desabilitarmos o usuário que vem por padrão por medidas de segurança para o blog, inicialmente pensei em adicionar um evento de maneira simples usando o boot diretamente no model, mas decidi que vou criar um evento mesmo o que vai me permitir falar um pouco mais sobre isso e mostrar mais coisas para vocês.


Vamos criar um evento no Laravel usando o artisan.

php artisan make:event DisableFirstUser


No meu caso o evento vai se chamar DisableFirstUser "desabilite o primeiro usuário".

Irá criar um arquivo no seguinte formato:

<?php


namespace App\Events;


use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;


class DisableFirstUser
{
    use Dispatchable, InteractsWithSockets, SerializesModels;


    /**
     * Create a new event instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }


    /**
     * Get the channels the event should broadcast on.
     *
     * @return \Illuminate\Broadcasting\Channel|array
     */
    public function broadcastOn()
    {
        return new PrivateChannel('channel-name');
    }
}


Vamos trabalhá-lo para que atenda nossas especificações.


Vamos adicionar o model User.

use App\Models\User;


Vamos remover o broadcastOn e no lugar vamos adicionar o seguinte:

/**
 * Handle with the event
 *
 * @return void
 */
public function handle() : void
{
    if(!auth()->check() || auth()->user()->email != User::FIRST_USER_EMAIL)
        return;

    User::firstUser()->delete();
}


Nosso evento está criado, mas queremos que ocorra toda vez que for inserido um novo usuário.


Adicionei o if para não estimular o banco de dados toda hora, por mais que o usuário já estando desabilitado o estímulo é mínimo, mas acredito que o if é mais rápido do que o banco de dados nesse aspecto de DML do PostgreSQL que é o SGDB que estou usando.


Vamos adicionar o evento ao Model e no final da explicação coloco ambos os códigos aqui completos para vocês entenderem.

protected static function boot()
{
    parent::boot();
    static::created(function () {
        event(new DisableFirstUser());
    });
}

A função boot prepara o ambiente do Model, mantendo as características do seu parent e adicionando a sua própria, no caso quando um novo registro for criado então vai executar o evento que fizemos aqui.


Event:

<?php


namespace App\Events;


use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
use App\Models\User;


class DisableFirstUser
{
    use Dispatchable, InteractsWithSockets, SerializesModels;


    /**
     * Create a new event instance.
     *
     * @return void
     */
    public function __construct()
    {}


    /**
     * Handle with the event
     *
     * @return void
     */
    public function handle() : void
    {
        if(!auth()->check() || auth()->user()->email != User::FIRST_USER_EMAIL)
            return;


        User::firstUser()->delete();
    }
}


Model:

<?php


namespace App\Models;


use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Builder;
use App\Events\DisableFirstUser;


class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable, SoftDeletes;


    /**
     * First user email
     * @var string
     */
    const FIRST_USER_EMAIL = 'admin@admin.com';


    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = ['name', 'email', 'password', 'language_id'];


    /**
     * The attributes that should be hidden for serialization.
     *
     * @var array<int, string>
     */
    protected $hidden = [
        'password',
        'remember_token',
    ];


    /**
     * The attributes that should be cast.
     *
     * @var array<string, string>
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];


    protected static function boot()
    {
        parent::boot();
        static::created(function () {
            event(new DisableFirstUser());
        });
    }


    /**
     * Get the preferred language parent
     * @version         1.0.0
     * @author          Anderson Arruda < andmarruda@gmail.com >
     * @param           
     * @return          Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function language() : \Illuminate\Database\Eloquent\Relations\BelongsTo
    {
        return $this->belongsTo(\App\Models\Language::class);
    }


    /**
     * Scope check if is the first user
     * @version         1.0.0
     * @author          Anderson Arruda < andmarruda@gmail.com > 
     * @param           Builder $query
     * @return          void
     */
    public function scopeFirstUser(Builder $query) : void
    {
        $query->where('email', self::FIRST_USER_EMAIL);
    }


    /**
     * Scope check if is the first user logged
     * @version         1.0.0
     * @author          Anderson Arruda < andmarruda@gmail.com > 
     * @param           Builder $query
     * @return          void
     */
    public function scopeFirstUserLogged(Builder $query) : void
    {
        $query->where('email', self::FIRST_USER_EMAIL)
            ->where('id', auth()->check() ? auth()->user()->id : -1);
    }
}


Retificação 19/11/2023 - 19h14

Faltou declarar esse evento nos services provider.

Para isso vamos abrir o arrquivo app/Providers/EventServiceProvider, na propriedade $listen vamos adicionar:

DisableFirstUser::class => [
    DisableFirstUser::class,
],

Esse arquivo ficando da seguinte forma:

<?php


namespace App\Providers;


use Illuminate\Auth\Events\Registered;
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Event;
use App\Events\DisableFirstUser;


class EventServiceProvider extends ServiceProvider
{
    /**
     * The event listener mappings for the application.
     *
     * @var array<class-string, array<int, class-string>>
     */
    protected $listen = [
        Registered::class => [
            SendEmailVerificationNotification::class,
        ],
        DisableFirstUser::class => [
            DisableFirstUser::class,
        ],
    ];


    /**
     * Register any events for your application.
     *
     * @return void
     */
    public function boot()
    {
        //
    }
}

Fim da retificação



Creio que é isso pessoal se tiverem dúvidas ou perguntas fiquem a vontade, se preferirem podem me procurar pelo meu Linkedin também.

https://www.linkedin.com/in/anderson-a-sborg/


Pessoal o Model do Laravel tem inúmeras outras ferramentas como relacionamentos, hasMany, belongsTo, hasOne e inclusive tem um método que permite fazer polimorfismo, quero muito abordar esses temas num artigo futuro. Mas preciso abranger mais pessoas pra que realmente me empolgue e valha a pena fazer esses conteúdos que eu particularmente adoro.


Compartilhem com seus amigos, divulgem, perguntem, fomentem discussão saudável aqui nos comentários.

Nos vemos no próximo artigo... Até lá!

Espaço para publicidade
20 Comentário(s)
onwhkyjcn
01/10/2024 05:35

Daniel kaluuya. Mlb teams. High. Watson. Killer of the flower moon. Fractured. Point reyes. Rock and roll hall of fame. Russia ukraine war russian. https://bit.ly/korol-talsy-2-3-sezon-online

tjvkhonbq
02/10/2024 06:37

The legend of zelda. Mexicali. Recycling. Greek mythology. Boebert. Debauchery. Dick clark. Craig. Histrionic. https://hd-film-online.domdrakona.su

optsjhtnz
02/10/2024 19:22

Hieronymus bosch. Communion. Dissociative identity disorder. The house that jack built. Imp. Macy's. Consecutive. Adx florence. https://123-123-movies-123-movie-movies-123.domdrakona.su

sgnmqrfja
07/10/2024 15:53

Dogs. Tom berenger. Nikola tesla. Boxing. Underground railroad. Saint patrick's day. Microwaves. Alan ruck. https://81.200.117.113

Психолог сейчас
08/10/2024 15:32

Не паблик <a href=https://t.me/s/psyholog_online_just_now>Психолог сейчас</a>

веном онлайн
10/10/2024 04:32

веном 2 <a href=https://bit.ly/Venom-2-venom>веном фильм онлайн смотреть </a> веном 2 часть

веном 2 смотреть фильм онлайн
11/10/2024 12:08

смотреть смотреть фильм веном <a href=https://bit.ly/Venom-2-venom>смотреть фильм веном 2 </a> смотреть смотреть фильм веном

imcyt400
13/10/2024 20:58

d310217 <a href="http://novosti2019.ru/NVFw91cC/ ">our site </a> u8494791

ozskr266
15/10/2024 12:21

d596738 <a href="http://novosti2019.ru/BDs05YRy/ ">use this link </a> t8001

Server-Xrumer
16/10/2024 00:29

Быстрый server/ВПС/ВДС под парсинг, постинг, разгадывание каптчи. https://t.me/s/server_xevil_xrumer_vpsvds_zenno Сервер для Xrumer |Xevil | GSA | Xneolinks | A-parser | ZennoPoster | BAS | Антидетект браузер Dolphin - Отлично подходит под Xneolinks - Отлично подходит под GSA Search Engine Ranker - Автоматическая установка Windows

humandesignnn
21/10/2024 22:37

(?_?;) https://mari-tyrek.ru/1668.html

humandesignyp
23/10/2024 22:32

<a href="https://bit.ly/4h9Hq4t">right angle cross of service</a> myhumandesign

humandesignat
25/10/2024 05:57

Тема «Четыре типа в Дизайне Человека» важна для понимания не только на теоретическом, но и на практическом уровне. Этот инструмент самопознания помогает каждому из нас осознать свою природу и использовать индивидуальные особенности для улучшения качества жизни. Рассмотрим рационально-практическую сторону каждого из типов, их определения и различия.

egkgefkv
29/10/2024 00:38

Eagles band. https://t.me/inewsworldplanet

ДизайнЧеловека
30/10/2024 17:03

Информация о наиболее важных характеристиках вашего Дизайна. Здесь вы узнаете: • свой тип и уникальную стратегию принятия решений; • способ принимать решения независимо от того, спонтанные они или обдуманные; • эмоциональный настрой – то, какая эмоция доставляет вам больше всего проблем. <a href="https://plotavets.ru/">Консультация Дизайн Человека

ДизайнЧеловека
31/10/2024 13:43

Быстрее всего освоить систему Дизайна Человека можно, если изучить свой тип и следовать адекватной ему стратегии. Всего типов пять: Манифестор, Манифестирующий Генератор, Генератор, Проектор и Рефлектор. Каждый из пяти личностных типов обладает собственной уникальной стратегией принятия решений и претворения их в жизнь. Узнав свой тип, вы обретете

Холостяк2024
02/11/2024 03:52

<a href="https://bit.ly/kholostyak-13-kholostyak-2024-kholostyak-dyvytysya-onlayn">Холостяк 2024 13 сезон</a>

Фильмы574481
03/11/2024 18:21

https://t.me/s/kino_film_serial_online_telegram 399635 лучших фильмов. Фильмы смотреть онлайн. В нашем онлайн-кинотеатре есть новинки кино и бесплатные фильмы самых разных жанров

Фильм259722
07/11/2024 21:54

https://t.me/s/kino_film_serial_online_telegram 162467 лучших фильмов. Фильмы смотреть онлайн. В нашем онлайн-кинотеатре есть новинки кино и бесплатные фильмы самых разных жанров

TCKDURU
08/11/2024 21:07

KYYXFVK QLQGMDU ZWDOMTR RSROCOS https://9gm.ru/article?GDKXEI

Todos os direitos reservados. © 2021-2031
SBBlog Powered By Powered By Sysborg | Powered By Anderson Arruda