У нас есть таблица invoices
, которая имеет поле Nullable number
.Наша бизнес-логика заключается в следующем.
Всякий раз, когда нам нужно взимать с клиента плату за обновление его услуг, мы высылаем ему счет-проформу.Счета-проформы распознаются атрибутом number
как пустой.
Всякий раз, когда мы хотим преобразовать счета-проформы (вручную или автоматически, потому что клиент заплатил), все, что мы в основном должны сделать, это определить новый номер и обновитьinvoice.number
.Эта функция прекрасно работает.
Теперь нам нужен маршрут GET /api/invoices/201900001
, который, как вы правильно догадались, должен получить счет WHERE number = 201900001
.
Итак, мы определили нашу модель счетаследующим образом:
class Invoice extends Model {
public function getRouteKeyName() {
return 'number';
}
}
работает блестяще.Но я думаю, вы знаете, что еще нам нужно.Нам также необходимо иметь возможность получать счета-проформы по маршруту GET /api/proformas/1
, где 1 фактически является id
, а не number
записи, поскольку вы знаете, что мы не присваиваем номер счетам-проформам, но назначаем только после того, как мы выставим счета-проформы и преобразуем их в счет-фактуру.
Таким образом, наш первый вопрос заключался в том, существует ли способ установить, к какому столбцу должен быть привязан параметр маршрута для отдельного маршрута, ноэто кажется невозможным, поэтому мы пошли другим путем.Если вы видите решение, которое позволяет мне поддерживать привязку к номеру и идентификатору в зависимости от маршрута, то непременно сообщите мне: -)
В любом случае, мы продолжили нашу работу, и тогда мы подумаличто ProformaInvoice
на самом деле является специфическим подтипом объекта Invoice
, поэтому мы пошли дальше и создали для этой цели новую модель:
Class ProformaInvoice extends Invoice {
public function getRouteKeyName() {
// override parent's behaviour back to the default
return 'id';
}
}
Вау - мы верили, что это должно было решить нашупроблемы, но это не так.Потому что угадайте, что - у нас также есть InvoiceElements, и они связаны с инвойсом.
Итак, у нас есть прекрасное отношение к модели инвойса:
Class Invoice extends Model {
public function getRouteKeyName() {
return 'number';
}
public function invoice_elements() {
return $this->hasMany(InvoiceElement::class);
}
}
Поскольку у нас теперь есть собственный ProformaInvoiceВ этой модели мы перенесли логику фактического начисления счета-проформы в этот класс (раньше это было на самой модели Invoice
):
public function ProformInvoice extends Invoice {
public function getRouteKeyName() {
return 'id';
}
public function convertToInvoice() {
$minNumber = (date('Y') * 100000) + 1;
DB::statement(
"UPDATE invoices inv
JOIN (
SELECT IF(IFNULL(MAX(number)+1,1) < " . $minNumber . ", " . $minNumber . ", MAX(number) + 1) AS newNumber
FROM invoices
) t
SET inv.number = t.newNumber, invoice_date = NOW(), updated_at = NOW()
WHERE id = " . $this->id;
);
return Invoice::find($this->id);
}
}
Мы думали, что мы действительно умны, потому что теперь наш CreateInvoiceController
работает так, и имеет для нас смысл:
Class CreateInvoiceController extends Controller {
public function create(CreateInvoiceRequest $request) {
$invoice = null;
DB::transaction(function() use($request, &invoice) {
$proforma = ProformaInvoice::create([
'due_date' => $request->get('due_date'),
'subtotal' => $request->get('subtotal'),
'vat' => $request->get('vat');
'total' => $request->get('total');
]);
$proforma->invoice_elements()->createMany($request->get('elements'));
$invoice = $proforma->convertIntoInvoice();
}, 1);
return InvoiceResource::make($invoice);
}
}
Хорошо, поэтому выполнение этого выбросило исключение, а именно Column not found: 1054 Unknown column 'proforma_invoice_id' in 'field list' (SQL: insert into 'invoice_elements'...
Это действительно имело смысл для меня, так как отношенияопределяется в модели Invoice и наследуется моделью ProformaInvoice.При попытке создания связанных моделей совершенно логично, что в нем не использовалось правильное имя столбца invoice_id
, поскольку мы не определяли явно внешний ключ при определении отношения, поэтому я решил, что у нас есть быстрое решение, а именно, явноопределите внешний ключ в определении отношения:
Class Invoice extends Model {
public function getRouteKeyName() {
return 'number';
}
public function invoice_elements() {
return $this->hasMany(InvoiceElement::class, 'invoice_id');
}
}
К моему большому удивлению, это не решает проблему;Я по-прежнему получаю сообщение об ошибке, что столбец proforma_invoice_id
не существует, хотя я явно устанавливаю определение внешнего ключа на invoice_id
для его определения ...
Я что-то пропускаю или это ошибкав рамках?
Вы бы посоветовали другой путь, который имеет больше смысла для вас?Для меня это имеет смысл сейчас, но может быть другое решение ...
Я мог бы просто не привязывать модель, а сам загрузить модель в контроллере, но я хотел бы сохранитьиспользуйте как можно более чистый код и по возможности используйте привязку модели при настройке маршрутов.
Если вы попали сюда - СПАСИБО за чтение.