Для начала давайте поговорим о том, что такое ORM. Не знаю, есть ли среди знакомых люди, не знающие этого понятия. В любом случае, это всего лишь научно-популярная наука. Полное название ORM — «Реляционное сопоставление объектов», что переводится как «Реляционное сопоставление объектов». Проще говоря, он использует объектно-ориентированные объекты для сопоставления данных в базе данных. В нашей реляционной базе данных строку данных можно рассматривать как объект, а всю таблицу — как список этого объекта. Это очень простое понимание ORM.
Hibernate в Java — это очень классический ранний фреймворк ORM. В Yii используется паттерн доменной модели Active Record. В Yii даже название этого компонента — непосредственно AR. Active Record по-китайски означает активную запись, ее особенностью является то, что класс модели соответствует таблице в базе данных. Фактически, Eloquent ORM в Laravel также является реализацией Active Record, которая сейчас также является основным направлением ORM.
Подготовив первые две статьи, мы можем легко управлять моделью в Laravel, но что действительно необходимо изменить, так это ваш взгляд на работу с базой данных. Думайте о данных в базе данных как об объектах языка программирования. Это основное содержание ORM.
Создать Модель мы можем вручную,Вы также можете использовать командную строку,Поскольку да система обучения,Затем мы также можем использовать командную строку для создания. Категория модели. Используйте таблицу из, как и раньше, но измените имя. На этот раз будет называться имя таблицы. m_test . Затем создаем соответствующую таблицу через командную строку Модель добрый.
php artisan make:model MTest
После выполнения команды мы увидим вновь созданный файл MTest.php в каталоге app/Models. Сгенерированный код выглядит следующим образом:
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class MTest extends Model
{
use HasFactory;
}
Ну, все очень просто: класс Модель успешно создан. Далее мы будем использовать его для добавления, удаляйте,изменяйте и проверяйтеиздействовать。
Во-первых, давайте посмотрим на новый пример.
Route::get('model/test/insert', function () {
$data = [
[
'name'=>'Peter',
'sex' => 1,
],
[
'name'=>'Tom',
'sex' => 1,
],
[
'name'=>'Susan',
'sex' => 2,
],
[
'name'=>'Mary',
'sex' => 2,
],
[
'name'=>'Jim',
'sex' => 1,
],
];
foreach ($data as $v) {
$model = new \App\Models\MTest();
$model->name = $v['name'];
$model->sex = $v['sex'];
$model->insertGetId();
$insertId = $model->id;
// $insertId = \App\Models\MTest::insertGetId($v);
echo $insertId, '<br/>';
}
});
// Base table or view not found: 1146 Table 'laravel.m_tests' doesn't exist
Выполните этот код напрямую и получите ошибку! ! Почему это? Я быстро проверил сообщение об ошибке и обнаружил, что таблица laravel.m_tests не существует. Друзья, не удивляйтесь, здесь нормально совершать ошибки. Почему? Во-первых, в приведенном выше классе Modal мы не указали имя таблицы, но платформа сопоставит имя таблицы на основе имени класса. Правило состоит в том, чтобы изменить регистр верблюда на имя змеи, например, MTest станет m_test. Вроде бы проблемы нет, но почему выдается ошибка, что таблица m_tests не существует? Это включает в себя концепцию Active Record, описанную выше. В AR класс соответствует таблице, а таблица состоит из нескольких строк данных. В английском именовании к числам во множественном числе обычно добавляется s. Поэтому, если имя таблицы сопоставляется автоматически, после преобразования большого верблюжьего регистра в конец имени таблицы будет добавлена буква s.
Хорошо, я понимаю, но тогда мы не сможем пользоваться часами? Нет-нет, это очень просто. Мы просто задали переменную классу модели, чтобы указать имя таблицы.
class MTest extends Model
{
use HasFactory;
protected $table = 'm_test';
}
Запустите указанную выше вставку еще раз, чтобы проверить, прошла ли вставка успешно? Я пошел и все равно получил ошибку. Давайте посмотрим на сообщение об ошибке.
// Unknown column 'updated_at' in 'field list'
Что это, черт возьми? В нашей таблице нет этого поля.
Фактически, это также значение по умолчанию Model механизм. для Laravel средний стандарт Eloquent Для класса Модель каждая таблица должна иметь два Поле и одно да. updated_at , другой created_at , соответственно, представляют собой два поля временных меток, используемые для записи времени создания и времени изменения данных. Фактически, лучше всего, чтобы все таблицы имели эти два поля, и многие серверные системы управления также должны иметь Создатель и Модификатор из записи. Все они предназначены для обеспечения безопасности данных и отслеживания записей. Если в вашей таблице из есть эти два слова «Полеиз», то существование Model Во время операции вы можете игнорировать работу этих двух полей. Система устанавливает их автоматически. Но в нашей сегодняшней демонстрации эти два поля не нужны, поэтому вы также можете установить свойство, чтобы отключить их. Model Автоматическая обработка для них.
class MTest extends Model
{
use HasFactory;
protected $table = 'm_test';
public $timestamps = false;
}
Все в порядке,Попробуйте еще раз. Наконец, да работает успешно, верно?,Давайте опубликуем модификацию, удаление, простой запрос и код.,Давайте посмотрим, как они работают вместе позже.
Route::get('model/test/update', function () {
$data = [
'name' => request()->name,
'sex' => request()->sex,
'id' => request()->id
];
if($data['id'] < 1 || !$data['name'] || !in_array($data['sex'], [1, 2])){
echo «Ошибка параметра»;
}
$model = \App\Models\MTest::find($data['id']);
$model->name = $data['name'];
$model->sex = $data['sex'];
$model->update();
echo «Модификация прошла успешно»;
});
Route::get('model/test/delete', function () {
$id = request()->id;
if($id < 1){
echo «Ошибка параметра»;
}
\App\Models\MTest::destroy($id);
echo «Удалить успешно»;
});
Route::get('model/test/list', function () {
$where = [];
if(request()->name){
$where[] = ['name', 'like', '%' . request()->name . '%'];
}
if(request()->sex){
$where[] = ['sex', '=', request()->sex];
}
$list = \App\Models\MTest::where($where)
->orderBy('id', 'desc')
->limit(10)
->offset(0)
->get()
->toArray();
dd($list);
});
Route::get('model/test/info', function () {
$id = (int)request()->get('id', 0);
$info = \App\Models\MTest::find($id);
dd($info);
});
Давайте сначала посмотрим на функцию вставки, которая является функцией верхнего кода. Мы создаем экземпляр MTest объект, затем присвойте значения его свойствам, а затем непосредственно save() Вот и все. Здесь странно существовать, мы не передали объекту первичный ключ при создании экземпляра и присвоении. id задание, но в save() После этого идентификатор У него есть значение, и это наши недавно вставленные данные. id , разве это не очень благородно? Да, это оно ORM изAdvantage, по сути, наш изэтот объект экземпляра был ибаза Часть данных в data связана. Обратите внимание на комментарий части кода, который мы используем MTest::insertGetId() Эту форму также можно успешно вставить, но она больше похожа на построитель запросов кстати, это не может полностью отразить ORM чувство, поэтому мы по-прежнему используем метод создания экземпляров объектов для работы.
Аналогично, при обновлении мы сначала передаем статический метод find() Найдите и верните объект данных, затем измените его свойства, а затем update() Вот и все. Обратите внимание, что это также можно использовать save() метод, его функция заключается в том, что его можно использовать для добавления или сохранения в построитель запросов В , такого метода нет, но есть аналогичный updateOrInsert() Метод, вы можете попробовать сами.
Функция удаления напрямую вызывает статический метод уничтожения(). Параметр, который она может получить, — это идентификатор первичного ключа, и здесь мы можем передавать несколько идентификаторов и другие различные методы записи для пакетного удаления. Вы также можете самостоятельно проверить официальную документацию.
Наконец, в запросе мы также видим что-то вроде построитель запросов из Цепная форма вызова, статическая через Модельиз where() Метод возвращает объект экземпляра и шаг за шагом строит весь запрос. Я считаю, что мне нет необходимости объяснять принцип этого, и построитель запросов Разница здесь в том, что Model Построено с самого начала, а не непосредственно через DatabaseManager Начало. Но на самом деле Model Внизу должен быть один DatabaseManager соответствует из Connector Это работает. Мы поговорим об этом позже, когда будем анализировать исходный код.
Видя это, чувствуете ли вы, что содержание первых двух статей очень важно? Если вы еще этого не поняли, пожалуйста, вернитесь и немедленно прочитайте содержание первых двух статей. Обучение происходит поэтапно. начните с самого начала, мы поговорим о слое модели. Эта куча вещей, вероятно, всех запутает. Далее идут демонстрации нескольких мелких операций, а в конце мы еще ставим анализ исходного кода.
Связанные Что означает операция? это вообще-то ибаза данныхиз Связанные операциида Это важноиз。существоватьстандартныйизбаза В структуре данных у нас есть понятие первичных внешних ключей, но, честно говоря, они существуют. MySQL Использование первичных и внешних ключей действительно очень редко. Кажется, у меня было такое впечатление до этого MySQL Не рекомендуется устанавливать связи между таблицами через первичные и внешние ключи. Мы изучим это подробно позже MySQL Прочтите соответствующие статьи для более глубокого изучения. Что касается того, правда ли это, у меня только впечатление. Если это неверно, пожалуйста, не обижайтесь. Мы исправим это, когда узнаем об этом позже.
Причина, по которой существует внешний ключ, заключается главным образом в том, что он может существовать до данных. Уровень данных поддерживает определенную связь, поэтому мы можем выполнять некоторые специальные операции, такие как определение базы данных. данныхизсобытиеили Запланированные задачи и тому подобное.из,илисуществоватьассоциацияудалитьизпора быть более эффективным。так Делатьиз Причина точно такая жеда Чтобы сохранить данныеизпоследовательностьичестность。
Конечно, в Laravel вы можете реализовать ассоциации первичных и внешних ключей в коде фреймворка, не делая строгих настроек на уровне базы данных.
class MTest extends Model
{
use HasFactory;
protected $table = 'm_test';
public $timestamps = false;
public function gender(){
return $this->belongsTo('App\Models\DbSex', 'sex');
}
}
DbSex Модель Мы строим для db_sex Таблица из Модель, эта таблица да. В предыдущей статье из использовался во время теста, причем использовался напрямую. код существования, мы определяем, получил один метод с именем gender() , а затем внутри return получил один belongsTo() В методе метод.существоватьэтот первый параметр да указывает, что из Модель должна быть связана, а второй параметр да соответствует из Поле. принадлежит Что означает это слово? На самом деле это подчиненный из средств, то есть, да сказал, мы сейчас являемся этой Модельиз sex Поле подчиненный db_sex поверхность. мы можем посмотреть belongsTo() Что делается в методе.
// laravel/framework/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php
public function belongsTo($related, $foreignKey = null, $ownerKey = null, $relation = null)
{
if (is_null($relation)) {
$relation = $this->guessBelongsToRelation();
}
$instance = $this->newRelatedInstance($related);
if (is_null($foreignKey)) {
$foreignKey = Str::snake($relation).'_'.$instance->getKeyName();
}
$ownerKey = $ownerKey ?: $instance->getKeyName();
return $this->newBelongsTo(
$instance->newQuery(), $this, $foreignKey, $ownerKey, $relation
);
}
Вы можете сами ознакомиться с приведенным выше содержанием метода. Главное, на что нам нужно обратить внимание, — это нижний. instance->newQuery() , видно, что нет, и дасоздан получил один построитель запросов . тогда пройди
// laravel/framework/src/Illuminate/Database/Eloquent/Relations/BelongsTo.php
public function addConstraints()
{
if (static::$constraints) {
$table = $this->related->getTable();
$this->query->where($table.'.'.$this->ownerKey, '=', $this->child->{$this->foreignKey});
}
}
// select * from `db_sex` where `db_sex`.`id` = ?
этот query из where Что значит условно? Это тот, что над нами SQL Условия запроса оператора. Просто спроси это db_sex изданных в таблицу, а затем вернуть полученный из результата объект обратно. Что касается этого ? Внутри из вещей да что, то да по нашему из MTest этот Model Внутри sex Полеиз значения для определения из, то есть да $this->child->{$this->foreignKey}этот раздел。$this->foreignKey Это в нашем верхнем коде belongsTo() Метод по второму параметру. Этот параметр является необязательным. Если он не заполнен, будет найден параметр с именем. sex_id из значения, конечно, существования да в наших данных нет этого Полеиз, поэтому указываем sex 。
Наконец, разберитесь с приведенной выше цепочкой вызовов,первый,Мы генерируем определение из MTest унаследован от laravel/framework/src/Illuminate/Database/Eloquent/Model.php Этот абстрактный класс, обратите внимание, что он абстрактно добрый. Тогда, существует это не абстрактный класс, используйте полученный. один laravel/framework/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php характеристики, то есть Trait документ。существоватьэтоизвда belongsTo() Метод из исходного кода. Далее, пройдите newRelatedInstance() Метод создает экземпляр отношения, то есть мы указываем из DbSex Модельиз объекта. Тогда просто позвони да newBelongsTo() метод генерирует laravel/framework/src/Illuminate/Database/Eloquent/Relations/BelongsTo.php Объект и запрос, и, наконец, возврат этого объекта.
Следующий вопрос – как использовать да и из.
Route::get('model/test/relationship', function () {
$id = (int)request()->get('id', 0);
$info = \App\Models\MTest::find($id);
dump($info);
dump($info->gender);
dump($info->gender->name); // женский
});
Использовать этот метод для связывания объектов очень просто, просто вызовите gender Просто атрибуты. Подождите, это неправильно, мы определяем изда в существующей Модели gender() метод,Как использовать атрибут издаон существует снаружи? Не волнуйся,Давайте еще раз посмотрим на исходный код,Посмотрите, как в рамках фреймворка вызов атрибутов превращается в вызов метода.
существовать MTest , мы ничего не видим, ведь мы сами пишем контент, поэтому нам нужно прийти к его базовому классу, как упомянуто во фронтенде, тому абстрактному классу laravel/framework/src/Illuminate/Database/Eloquent/Model.php . В категории «существованиеэтот» вы найдете множество магических методов, таких как __get() этотметод.
public function __get($key)
{
return $this->getAttribute($key);
}
Вы еще помните эффект этих магических методов? Это содержание, которое я представил в своей первой статье. Если вы не помните, вы можете перейти к . 【PHPиз Эти волшебные методы (1)】https://mp.weixin.qq.com/s/QXCH0ZttxhuEBLQWrjB2_A Просмотрите это. Я не буду здесь много объяснять. В любом случае, если объект дасуществовать вызывает из, а изда вызывается без явного написания атрибута из в шаблоне класса существования, вы придете к этому. __get() магия в Методе. Кажется, что дальше все будет легко, идите прямо. getAttribue() Продолжайте рассматривать метод.
// laravel/framework/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php
public function getAttribute($key)
{
if (! $key) {
return;
}
if (array_key_exists($key, $this->attributes) ||
array_key_exists($key, $this->casts) ||
$this->hasGetMutator($key) ||
$this->isClassCastable($key)) {
return $this->getAttributeValue($key);
}
if (method_exists(self::class, $key)) {
return;
}
return $this->getRelationValue($key);
}
этот getAttribute() Метод также дасуществовать Model абстрактный класс из другого Trait Определение из. На самом деле, этот код уже очень понятен. key Просто верните пустой контент, если key Сохраните существование в текущем классе этой Модели из связанных атрибутов, а затем верните его после вызова некоторых методов обработки. Далее, если это key да Model При вызове метода базового класса напрямую возвращается пустое содержимое. Обратите внимание: здесь снова используется техника, которую мы изучили ранее. Видите? это судья издаэтот key да Нода Абстрактный базовый класс laravel/framework/src/Illuminate/Database/Eloquent/Model.php , вместо да определим из MTest , используйте издаон self 。Я верю, что ты всегда будешь сопровождать меня в учебеиз Мои друзья сразу поймут,[Позднее статическая привязка стала использоваться в PHP]https://mp.weixin.qq.com/s/N0rlafUCBFf3kZlRy5btYA Дайте ему хороший обзор.
Наконец, мы подошли к методу getRelationValue().
// laravel/framework/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php
public function getRelationValue($key)
{
if ($this->relationLoaded($key)) {
return $this->relations[$key];
}
if (method_exists($this, $key) ||
(static::$relationResolvers[get_class($this)][$key] ?? null)) {
return $this->getRelationshipFromMethod($key);
}
}
Обратите внимание, здесь из method_exsits() Что стало с параметром Чжонгиза? Да, он также имеет функцию позднего статического связывания, которая здесь используется. $this , теперь здесь существование относится к объекту, который да MTest Понятно,В этой части нет ничего плохого, верно?,Идеально подходит для поздней статической привязки приложения.
Наконец, перейдите к методу getRelationshipFromMethod().
// laravel/framework/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php
protected function getRelationshipFromMethod($method)
{
$relation = $this->$method();
if (! $relation instanceof Relation) {
if (is_null($relation)) {
throw new LogicException(sprintf(
'%s::%s must return a relationship instance, but "null" was returned. Was the "return" keyword used?', static::class, $method
));
}
throw new LogicException(sprintf(
'%s::%s must return a relationship instance.', static::class, $method
));
}
return tap($relation->getResults(), function ($results) use ($method) {
$this->setRelation($method, $results);
});
}
$relation Переменная сначала выполняет ту, которую мы определили из gender() Метод возвращает результат, то есть да получает вышеуказанный результат. BelongsTo() объект. Тогда дойди до конца из tap() в, нажмите() даон Laravel Определите глобальные функции в рамках, и env() функциясуществовать Вместеиз,Он из функции передает первый параметр в качестве второго параметра из параметра во второй параметр.,и после выполнения второго параметра,Верните первый параметр еще раз. Немного запутанно? Фактически значение первого параметра даон,а затем поместите его во второй параметр,этотпараметрдаонперезвонитьфункция,Затем используйте это значение для выполнения других операций через функцию обратного вызова. Этот абзац может быть недостаточно ясен,Вы можете сами проверить исходный код и отладить его, чтобы понять.
В кодексе существование да называется первым BelongsTo объект из getResults() Метод получения истинной ассоциации DbSex этот Model объект, а затем передать его через функцию обратного вызова setRelation() привязать к laravel/framework/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php этот Trait из $relations свойства для удобства последующего использования. наконец tap() Функция также будет обрабатывать значение первого переданного ранее параметра, которое является окончательным значением. DbSex Затем объект возвращается полностью в __get() середина,так,Вся цепочка звонков завершена.
Сегодня мы узнаем изконтентда ORM из концепции и базового использования из Моделиз, плюс получил одна связанная функция — анализ исходного кода. Конечно, это простейшая связь один-к-одному, Очень сложные ассоциации также можно реализовать в рамках Laravel.,в том числе один ко многим,многие к одному,Ассоциация «многие ко многим»,Вам решать, как использовать это содержимое.,Ведь основная цель нашей статьи — понять, как они работают.,Ведь принципы все прояснены,Другие, кому интересно, могут продолжить углубленный анализ самостоятельно. В следующей статье мы продолжим изучать Модельиз и проанализируем весь исходный код Модельиз.
Справочная документация:
https://learnku.com/docs/laravel/8.x/eloquent/9406