Как получить последний вставленный неинкрементный идентификатор, используя красноречие в Laravel?

У меня две модели Customer и Address. Мой Customer имеет неинкрементный первичный ключ и относится к типу string, то есть customer_id. Связь между этими двумя моделями - один ко многим, что означает для одного customer множество addresses, например: адрес счета-фактуры, адрес доставки, текущий адрес и т. д. Моя модель Customer показана ниже:

Customer.php

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Customer extends Model
{
    protected $keyType = 'string';
    protected $primaryKey = 'customer_id';
    public $incrementing = false;

    public function addresses()
    {
        return $this->hasMany('App\Address','customer_id');
    }
}

И моя модель адреса показана ниже:

Address.php

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Address extends Model
{
    //
    public $timestamps = false;
    // protected $table = "addresses";

    public function customer()
    {
        return $this->belongsTo('App\Customer');
    }
}

А ниже показана миграция для таблицы моих клиентов.

миграция для таблицы клиентов

<?php

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

class CreateCustomersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('customers', function (Blueprint $table) {
            $table->string('customer_id');
            $table->string('name');
            $table->string('type');
            $table->date('dob');
            $table->type('country_code');

            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('customers');
    }
}

Еще следует отметить, что мой customer_id является инкрементным в том смысле, что я создал отдельную таблицу, а именно customer_sequence, которая является автоматически инкрементной, и перед вставкой записи я добавляю ее с двухсимвольным кодом с помощью триггера, а затем помещаю в свою таблицу customers. Моя миграция customer_sequence показана ниже.

customer_sequence Миграция

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

class CreateSequenceCustomers extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('sequence_customers', function (Blueprint $table) {
            $table->increments('id');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('sequence_customers');
    }
}

И триггер, который я использовал для вставки увеличивающегося идентификатора строки, выглядит следующим образом:

Миграция для триггера customer_id

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

class CreateTriggerCustomers extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        DB::unprepared("
        CREATE TRIGGER tg_customer_insert
            BEFORE INSERT ON customers
            FOR EACH ROW
            BEGIN
                INSERT INTO sequence_customers(id) VALUES (NULL);
                IF NEW.type ='Private' THEN
                    SET NEW.customer_id = CONCAT(NEW.country_code, LPAD(LAST_INSERT_ID(), 5, '0'));
                ELSEIF NEW.type='Business' THEN
                    SET NEW.customer_id = CONCAT(NEW.country_code, LPAD(LAST_INSERT_ID(), 5, '0'));
                ELSEIF NEW.type='Reseller' THEN
                    SET NEW.customer_id = LPAD(LAST_INSERT_ID(), 5, '0');
                ELSEIF NEW.type='Distributor' THEN
                    SET NEW.customer_id = LPAD(LAST_INSERT_ID(), 5, '0');
                ELSEIF NEW.type='Other' THEN
                    SET NEW.customer_id = LPAD(LAST_INSERT_ID(), 5, '0');
                END IF;
                IF NEW.credit_amount > NEW.credit_limit THEN
                   SET NEW.credit_limit_exceeded=TRUE;
                ELSE
                    SET NEW.credit_limit_exceeded=FALSE;
                END IF;
            END
        ");
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        DB::unprepared('DROP TRIGGER IF EXISTS tg_customer_insert');
    }
}

Теперь, когда я сохраняю данные клиента и пытаюсь получить id из модели клиента, он возвращает мне null. Мой контроллер выглядит так, как показано ниже:

CustomerController.php

public function store(Request $request)
{
    $customer = new Customer;
    $invoiceAddress = new Address;
    $deliveryAddress = new Address;

    $customer->name = $request->name;
    $customer->type = $request->type;
    $customer->dob = $request->dob;
    $customer->country_code=$request->country_code;
    $customer->save();

    $deliveryAddress->street_name_no = $request->street_name_no;
    $deliveryAddress->city = $request->city;
    $deliveryAddress->country = $request->country;

    //This throws error customer_id cannot be null integrity constraint
    $deliveryAddress->customer_id = $customer->customer_id;
    $deliveryAddress->save();
}
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
0
0
985
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Это связано с тем, что вы присваиваете значения запроса переменной клиента.

$customer=new Customer;

$customer=$request->name;
$customer=$request->type;
$customer=$request->dob;
$customer->save();

Когда вы вызываете save(), вы фактически вызываете save() в строке. Исправьте это, указав заполняемые свойства в вашей модели Customer. Это всего лишь пример.

$customer = new Customer();

$customer->name = $request->name;
$customer->type = $request->type;
$customer->dob  = $request->dob;
$customer->save();

После этого $customer->customer_id не должен быть нулевым.

Обновлено: не удалось заметить следующую строку:

public $incrementing = false;

это означает, что во время создания вашего Customer вам также придется предоставить customer_id, поскольку он больше не имеет автоматического увеличения.

Я также более внимательно изучил API. Похоже, Laravel на этом этапе не узнает об атрибуте, установленном триггером. Вы можете попробовать использовать модель refresh(), которая будет извлекать новые атрибуты из БД, и, если ваши триггеры работают нормально, вы должны получить обратно customer_id.

По сути, просто добавьте эту строку перед добавлением адреса доставки.

$customer->refresh();

Я также заметил, что у вас нет никакой логики для перенаправления пользователя обратно при успешном сохранении. Я подозреваю, что именно поэтому он выдает ошибку 404, поскольку тот же маршрут не определен для запроса GET.

public function store(Request $request)
{
    $customer        = new Customer;
    $invoiceAddress  = new Address;
    $deliveryAddress = new Address;

    $customer->name = $request->name;
    $customer->type = $request->type;
    $customer->dob  = $request->dob;
    $customer->country_code = $request->country_code;

    $customer->save();

    $customer->refresh(); 

    $deliveryAddress->street_name_no = $request->street_name_no;
    $deliveryAddress->city = $request->city;
    $deliveryAddress->country = $request->country;


    $deliveryAddress->customer_id = $customer->customer_id;
    $deliveryAddress->save();

    return back()->with('success', 'Success message here');
}

Отредактировано снова:

Как видно из документа, метод refresh() выглядит следующим образом:

/**
 * Reload the current model instance with fresh attributes from the database.
 *
 * @return $this
 */
public function refresh()
{
    if (! $this->exists) {
        return $this;
    }

    $this->setRawAttributes(
        static::newQueryWithoutScopes()->findOrFail($this->getKey())->attributes
    );

    $this->load(collect($this->relations)->except('pivot')->keys()->toArray());

    $this->syncOriginal();

    return $this;
}

Как видно из следующей строки:

static::newQueryWithoutScopes()->findOrFail($this->getKey())->attributes

При обновлении модели он попытается найти или потерпит неудачу (404). Я подозреваю, что в этом случае он не может получить соответствующий ключ, и поэтому он не работает. Думаю, в данном случае вам придется брать customer_id из таблицы sequence_customers.

Возможно, вам удастся уйти, сделав что-нибудь вроде следующего:

// Assuming SequenceCustomer is the model name
$latest = \App\SequenceCustomer::latest()->first(); 

// and then you would be able to access the latest customer_id by doing the following

$customer_id = $latest->customer_id;

Очевидно, что это не масштабируемое решение, но я не очень уверен, как еще решить эту конкретную проблему :)

извините, что это была опечатка, я обновил ее, пожалуйста, взгляните на нее.

DevGuy 30.12.2018 19:02

Отредактировал свой ответ.

Mozammil 30.12.2018 19:15

Я упомянул в своем вопросе, что я использую последовательность из другой таблицы, которая называется «клиентская последовательность», в которой есть автоинкрементный идентификатор, который я использую в триггере, а затем добавление символа кода для ex SA001 используется в качестве первичного ключа в моем клиенте Таблица.

DevGuy 30.12.2018 19:24

Снова отредактировал свой ответ.

Mozammil 30.12.2018 19:47

Это не решает мою проблему, теперь я получаю сообщение о том, что страница не найдена.

DevGuy 31.12.2018 05:57

Я отредактировал свой вопрос и показал миграцию для customer_sequence и триггера.

DevGuy 31.12.2018 06:00

404 может не иметь отношения. Запись была сохранена правильно?

Mozammil 31.12.2018 06:29

да, запись клиента была вставлена, но после того, как я обновился перед вставкой адресных данных, она выдала мне эту ошибку

DevGuy 31.12.2018 06:38

Ваш вопрос касался того, что запись не вставляется, что теперь исправлено. Однако я также отредактировал свой ответ, включив в него возможную причину, по которой вы получаете 404.

Mozammil 31.12.2018 06:52

Все еще та же проблема, не удается перенаправить на ту же страницу, ошибка 404-я страница снова не найдена. Я могу сохранить клиента, но не могу адрес.

DevGuy 31.12.2018 06:56

Снова отредактировал ответ :)

Mozammil 31.12.2018 08:35

Это сработало, но не сработает, если нет столбца для метки времени.

DevGuy 31.12.2018 08:40

Вы можете отсортировать его по DESC в поле customer_id и получить самую последнюю.

Mozammil 31.12.2018 08:42

Да, это тоже может быть одним из решений, спасибо за помощь :)

DevGuy 31.12.2018 08:49

Другие вопросы по теме