Может войдёшь?
Черновики Написать статью Профиль

Руководство по Laravel Eloquent ORM

перевод

Eloquent — очень мощный и впечатляющий ORM (Object-Relational Mapper – слой объектно-реляционного отображения) в Laravel. Если вы знаете, как работать с объектами в PHP, значит, вы знаете, как работать с Eloquent. Нельзя сказать, что это очень просто, но тем не менее у нас есть самый элегантный синтаксис PHP для работы с моделями в Eloquent. Eloquent — довольно большая тема для разговора, и честно говоря, наверное, нам следовало бы пройти через некоторые составляющие части, чтобы дойти до самого Eloquent, но мы так не поступаем. Мы сразу ныряем с головой, надеясь, что выплывем.

Таблица БД для отображения модели Eloquent

В Laravel каждая модель Eloquent представляет одну таблицу БД. Но важно отметить, что даже при том, что одна модель отображает одну таблицу, мы чаще будем использовать комбинации моделей при получении статей, например, или задач, или записей в блоге. Используя отношения, мы можем запрашивать несколько таблиц, для получения требуемого результата.

От класса DB к Eloquent

В прошлом руководстве мы рассмотрели, как сделать базовые CRUD в Laravel с помощью класса DB прямо из коробки. Вспомните, мы даже не создали ни одной модели для этого, функциональность уже была там прямо из коробки. Это впечатляет. Двигаемся дальше, теперь мы можем определить некоторые модели, и сделаем это, наследуя Eloquent.

Давайте построим нашу первую модель Eloquent

Мы будем иметь дело с художниками (PHPPainter) и картинами (PHPPainting), поэтому сначала создадим нашу модель PHPPainter, но перед тем как мы создадим наши модели, давайте настроим миграции таблиц нашей БД вот так:

PHP
<?php
//  Таблица художников

use Illuminate\Database\Schema\Blueprint;
use 
Illuminate\Database\Migrations\Migration;

class 
CreatePaintersTable extends Migration {

    
/**
     * Запуск миграций.
     *
     * @return void
     */
    
public function up()
    {
        
Schema::create('painters', function(Blueprint $table)
        {
            
$table->increments('id');
            
$table->string('username')->unique();
            
$table->text('bio');
            
$table->timestamps();
        });
    }

    
/**
     * Откат миграций.
     *
     * @return void
     */
    
public function down()
    {
        
Schema::drop('painters');
    }

}

<?
php
//  Таблица картин

use Illuminate\Database\Schema\Blueprint;
use 
Illuminate\Database\Migrations\Migration;

class 
CreatePaintingsTable extends Migration {

    
/**
     * Запуск миграций.
     *
     * @return void
     */
    
public function up()
    {
        
Schema::create('paintings', function(Blueprint $table)
        {
            
$table->increments('id');
            
$table->string('title');
            
$table->text('body');
            
$table->integer('painter_id');
            
$table->timestamps();
        });
    }

    
/**
     * Откат миграций.
     *
     * @return void
     */
    
public function down()
    {
        
Schema::drop('paintings');
    }

}

Давайте запустим наши миграции, используя shphp artisan migrate.

Здорово! Теперь мы можем создать модель и внести некоторые данные в нашу базу. Следующая строка создаст модель PHPPainter, которая будет отображать таблицу базы данных painters:

PHP
class Painter extends Eloquent {}

Итак, мы создали нашу модель Eloquent, знаю, было очень непросто набрать столько кода. Давайте посмотрим, что даёт нам одна эта маленькая строчка кода, используя отражение для изучения нашего нового объекта.

PHP
Route::get('/', function()
{

  
$reflection = new ReflectionClass('Painter');  //  обзор методов и констант любого класса

  
print_r($reflection->getMethods());

});

Этот код выдаст 164 метода, которые вы найдёте в Laravel Eloquent API — это немного обескураживает. Но как говорится, спокойствие, только спокойствие. Для начала мы посмотрим только на некоторые из них. Поскольку мы уже рассмотрели настройку CRUD в Laravel 4 используя класс DB, почему бы теперь нам не взглянуть на настройку CRUD с помощью Eloquent?

PHP
//  получаем запросы и выводим их для ознакомления
Event::listen('illuminate.query', function($sql) {
    
var_dump($sql);
});

Это позволит нам видеть все запросы, которые создаёт для нас Laravel. Это поможет нам разобраться.

Создание

В Eloquent мы можем вставлять новые записи в БД несколькими способами, но мой любимый синтаксис — с использованием метода PHPsave():

PHP
Route::get('/', function()
{
    
$painter = new Painter;
    
$painter->username 'Leonardo Da Vinci';
    
$painter->bio 'Художник ренессанса, учёный, изобретатель и не только.';
    
$painter->save();
});
sqlstring ‘insert into painters (username, bio, updated_at, created_at) values (?, ?, ?, ?)’ (length=90)

Выборка (Select)

Теперь давайте посмотрим на нашу новую запись, выбрав данные с помощью PHPall() и PHPfirst():

PHP
Route::get('/', function()
{
    
$painters Painter::all()->first();

    echo 
$painters->username.'<br>';
    echo 
$painters->bio;

});
sqlstring ‘select * from painters‘ (length=24)
Leonardo Da Vinci
Художник ренессанса, учёный, изобретатель и не только.

Изменение

Давайте перейдем к обновлению. Я предлагаю добавить дефис в фамилию. Заметьте, что это не какой-то конкретный метод обновления, а скорее выборка, изменение атрибута, и использование метода сохранения, вот так:

PHP
Route::get('/', function()
{
    
$painters Painter::all()->first();
    
$painters->username 'Leonardo Da-Vinci';
    
$painters->save();
});
sqlstring ‘select * from painters‘ (length=24)
string ‘update painters set username = ?, updated_at = ? where id = ?’ (length=69)

Удаление

Удалять записи в Eloquent супер просто. Смотрите:

PHP
Route::get('/', function()
{
    
$painters Painter::all()->first();
    
$painters->delete();
});
sqlstring ‘select * from painters‘ (length=24)
string ‘delete from painters where id = ?’ (length=37)

Вот так — бац! — и Леонардо больше нет в БД.

Связи в Eloquent

Связи являются ключевым компонентом в Eloquent, но сначала нам нужно еще больше художников. Давайте добавим их:

PHP
Route::get('/', function()
{
    
$painter = new Painter;
    
$painter->username 'Leonardo Da Vinci';
    
$painter->bio 'Renaissance painter, scientist, inventor, and more. Da Vinci is one of most famous painters for his iconic Mona Lisa and Last Supper.';
    
$painter->save();

    
$painter = new Painter;
    
$painter->username 'Vincent Van Gogh';
    
$painter->bio 'Dutch post-impressionist painter. Famous paintings include: Sunflowers, The Starry night, Cafe Terrace at Night.';
    
$painter->save();

    
$painter = new Painter;
    
$painter->username 'Rembrandt';
    
$painter->bio 'One of greatest painters, admired for his vivid realism. Famous paintings include The Jewish Bride, The Storm of the sea of Galilee';
    
$painter->save();
});
sqlstring ‘insert into painters (username, bio, updated_at, created_at) values (?, ?, ?, ?)’ (length=90)
string ‘insert into painters (username, bio, updated_at, created_at) values (?, ?, ?, ?)’ (length=90)
string ‘insert into painters (username, bio, updated_at, created_at) values (?, ?, ?, ?)’ (length=90)

Отлично! Мы знаем, что художники, скорее всего, создали несколько картин. Для краткости я покажу только один фрагмент, показывающий как можно вставить картину. Сразу отмечу, что для наших целей ID Леонардо да Винчи — painter_id 2, ID Винсента Ван Гога — painter_id 3, и ID Рембрандта — painter_id 4. Именно поле painter_id в таблице картин помогает нашим отношениям. Нам нужно помнить об этом, при построении методов для выборки данных из нашей базы данных с помощью отношений.

Пример вставки картины:

PHP
Route::get('/', function()
{
    
$painter Painter::find(4);

    
$painting = new Painting;
    
$painting->title 'The Storm on the Sea of Galilee';
    
$painting->body 'The Storm on the Sea of Galilee is a painting from 1633 by the Dutch Golden Age painter Rembrandt van Rijn that was in the Isabella Stewart Gardner Museum of Boston, Massachusetts, United States, prior to being stolen on March 18, 1990.';
    
$painting->painter_id $painter->id;
    
$painting->save();
});

Примечание: Мы выполняем вариации этого кода несколько раз, чтобы у каждого художника было, по крайней мере, 2 картины в БД.

hasMany

У художника обычно много своих картин, как у писателя много книг, или у курицы много яиц. В Laravel мы можем задать такие отношения в нашей модели вот так:

PHP
<?php
class Painter extends Eloquent {

    public function 
paintings()
    {
        return 
$this->hasMany('Painting');
    }

}

Вот отличный трюк, который поможет вам запомнить, как это работает. Начинается с ключевого слова PHP$this, затем идёт имя класса файла, далее метод PHP$this, и затем переданная модель. В нашем случае это будет звучать так: This PHPPainter hasMany PHPPainting (у этого художника много картин). Видите, как это работает?

belongsTo

Верно и обратное, каждая картина должна быть нарисована художником. Можно сказать, что картина принадлежит (PHPbelongsTo) художнику. Посмотрим на эту модель:

PHP
<?php
class Painting extends Eloquent {

    public function 
painter()
    {
        return 
$this->belongsTo('Painter');
    }

}

Здесь мы можем использовать тот же трюк: (this|имя файла класса|имя метода|имя переданной модели). В нашем случае это будет звучать так: This PHPPainting belongsTo PHPPainter (эта картина принадлежит художнику).

Отличная работа :)

Динамические методы

Теперь, когда мы настроили наши модели для представления обоих отношений — hasMany и belongsTo, мы можем начать запрашивать данные из БД очень умными способами. Например, с помощью динамических методов и отношений, которые мы только что создали, мы можем сказать базе данных пойти, взять картины Леонардо да Винчи и вернуть их нам. Давайте посмотрим:

PHP
Route::get('/', function()
{
    
$painter Painter::whereUsername('Leonardo Da Vinci')->first();

    foreach(
$painter->paintings as $painting){
        echo 
$painting->title.'<br>';
        echo 
$painting->body.'<br><br>';
    }

});
sqlstring ‘select * from painters where username = ? limit 1′ (length=53)
string ‘select * from paintings where paintings.painter_id = ?’ (length=60)

Mona Lisa
Мона Лиза - портрет женщины работы итальянского художника Леонардо да Винчи, который считается “самым известным, самым посещаемым, самым упоминаемым, самым воспетым, самым пародируемым произведением искусства в мире

Last Supper
Тайная вечеря - роспись конца 15 века в трапезной монастыря Санта-Мария делле Грацие в Милане работы Леонардо да Винчи. Предположительно работа над произведением была начата около 1495 года, и оно стало частью общей схемы реконструкции церкви и ее монастырских зданий покровителя Леонардо - Лодовико Сфорца, герцога Миланского.

Обратите внимание на метод whereUsername, я не видел его раньше. И вы тоже, это потому что в Laravel вы можете комбинировать условие where с именем таблицы и передавать строку, которую ищете. Ошеломляюще! Вот ваш динамический метод. Что касается отношения, то это сработает, потому что мы сказали нашей модели PHPPainter, что у этого художника много картин.

Теперь давайте сделаем обратное, спросим у базы данных что-нибудь такое: «Кто нарисовал Поедателей картофеля?» С теми отношениями в модели PHPPainting, которые мы задали, такими как эта картина принадлежит художнику, мы можем также сделать и обратное:

PHP
Route::get('/', function()
{
    
$painting Painting::whereTitle('The Potato Eaters')->first();

    echo 
Painter::find($painting->painter_id)->username;

});
sqlstring ‘select * from paintings where title = ? limit 1′ (length=51)
string ‘select * from painters where id = ? limit 1′ (length=47)
Vincent Van Gogh

Ну конечно! Винсент Ван Гог — тот художник, который написал картину «Поедатели картофеля». Приведённый код — долгий способ для этого. Видите ли, когда мы создаём оба отношения, мы можем комбинировать модели для достижения любого поля обеих таблиц, проходя через них. Так как мы создали экземпляр модели PHPPainting в PHP$painting, мы можем теперь пройти через модель PHPPainter до любого поля в этой таблице. Как? Вот так:

PHP
Route::get('/', function()
{
    
$painting Painting::whereTitle('The Potato Eaters')->first();

    echo 
$painting->painter->username.'<br>';
    echo 
$painting->painter->bio;

});
sqlstring ‘select * from paintings where title = ? limit 1′ (length=51)
string ‘select * from painters where painters.id = ? limit 1′ (length=58)
Vincent Van Gogh
Голландский пост-импрессионист. Известные картины: Подсолнухи, Звёздная ночь, Ночная терраса кафе.

Заметьте, единственная модель, для которой понадобился экземпляр, это модель Painting, хотя мы с лёгкостью обращаемся и к полям таблицы художников, потому что проходим через неё.

Используйте ваше воображение, и вы сможете спросить у БД практически всё, что пожелаете, для этого надо всего лишь немного проб и ошибок. Давайте скажем базе данных «Выдай мне все картины, которые у тебя есть, и скажи мне, кто нарисовал каждую из них». Вас понял, будет сделано.

PHP
Route::get('/', function()
{
    
$paintings Painting::all();

    foreach(
$paintings as $painting){
        echo 
$painting->painter->username;
        echo 
' painted the ';
        echo 
$painting->title;
    }

});
sqlstring ‘select * from paintings‘ (length=25)
string ‘select * from painters where painters.id = ? limit 1′ (length=58)
Leonardo Da Vinci painted the Mona Lisa
string ‘select * from painters where painters.id = ? limit 1′ (length=58)
Leonardo Da Vinci painted the Last Supper
string ‘select * from painters where painters.id = ? limit 1′ (length=58)
Vincent Van Gogh painted the The Starry Night
string ‘select * from painters where painters.id = ? limit 1′ (length=58)
Vincent Van Gogh painted the The Potato Eaters
string ‘select * from painters where painters.id = ? limit 1′ (length=58)
Rembrandt painted the The Night Watch
string ‘select * from painters where painters.id = ? limit 1′ (length=58)
Rembrandt painted the The Storm on the Sea of Galilee

Обратите внимание, как много запросов поступает в нашу БД. Возможно, это не лучший вариант. Лучше сделать это, используя нетерпеливую загрузку (eager loading) с помощью метода PHPwith:

PHP
Route::get('/', function()
{
    
$paintings Painting::with('painter')->get();

    foreach(
$paintings as $painting){
        echo 
$painting->painter->username;
        echo 
' painted the ';
        echo 
$painting->title;
        echo 
'<br>';
    }

});
sqlstring ‘select * from paintings‘ (length=25)
string ‘select * from painters where painters.id in (?, ?, ?)’ (length=59)
Leonardo Da Vinci painted the Mona Lisa
Leonardo Da Vinci painted the Last Supper
Vincent Van Gogh painted the The Starry Night
Vincent Van Gogh painted the The Potato Eaters
Rembrandt painted the The Night Watch
Rembrandt painted the The Storm on the Sea of Galilee

Теперь намного круче. 2 запроса и готово.

Что ж, этого достаточно. Есть ещё много вещей в Laravel для изучения, но надеюсь, это тоже будет полезно.

Как вы считаете, полезен ли этот материал? Да Нет

Комментарии (2)

DenniLa2

Подскажите, куда вставить код:

//  получаем запросы и выводим их для ознакомления
Event::listen('illuminate.query', function($sql) {
    var_dump($sql);
});

что-бы видеть исполняемые запросы?

Proger_XP

Куда угодно — в сервис-провайдер вашего приложения или в один из start-файлов.

Написать комментарий

Разметка: ? ?

Авторизуйся, чтобы прокомментировать.