У меня две модели 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();
}






Это связано с тем, что вы присваиваете значения запроса переменной клиента.
$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;
Очевидно, что это не масштабируемое решение, но я не очень уверен, как еще решить эту конкретную проблему :)
Отредактировал свой ответ.
Я упомянул в своем вопросе, что я использую последовательность из другой таблицы, которая называется «клиентская последовательность», в которой есть автоинкрементный идентификатор, который я использую в триггере, а затем добавление символа кода для ex SA001 используется в качестве первичного ключа в моем клиенте Таблица.
Снова отредактировал свой ответ.
Это не решает мою проблему, теперь я получаю сообщение о том, что страница не найдена.
Я отредактировал свой вопрос и показал миграцию для customer_sequence и триггера.
404 может не иметь отношения. Запись была сохранена правильно?
да, запись клиента была вставлена, но после того, как я обновился перед вставкой адресных данных, она выдала мне эту ошибку
Ваш вопрос касался того, что запись не вставляется, что теперь исправлено. Однако я также отредактировал свой ответ, включив в него возможную причину, по которой вы получаете 404.
Все еще та же проблема, не удается перенаправить на ту же страницу, ошибка 404-я страница снова не найдена. Я могу сохранить клиента, но не могу адрес.
Снова отредактировал ответ :)
Это сработало, но не сработает, если нет столбца для метки времени.
Вы можете отсортировать его по DESC в поле customer_id и получить самую последнюю.
Да, это тоже может быть одним из решений, спасибо за помощь :)
извините, что это была опечатка, я обновил ее, пожалуйста, взгляните на нее.