Что касается моего предыдущего вопроса, я узнал, что из-за допущенной мной ошибки Laravel генерирует неправильный SQL-запрос:
select * from "companies" where "companies"."id" = '9c54986f-8284-4da9-b826-c7a723de279b' and "companies"."deleted_at" is null and "company_id" = '9c54986f-8284-4da9-b826-c7a723de279b'
Проблема здесь в том, что company_id не существует в companies; однако запрос не генерирует ошибку при запуске, он просто не возвращает результата.
Полагаю, проблема здесь в том, что "company_id" рассматривается как литерал, а не как ссылка на столбец; если я удалю кавычки, я получу правильную ошибку:
Error: in prepare, no such column: company_id (1)
Я также получаю правильную ошибку, если добавляю префикс таблицы к имени столбца:
sqlite> select * from "companies" where "companies"."id" = '9c54986f-8284-4da9-b826-c7a723de279b' and "companies"."deleted_at" is null and "companies"."compa
ny_id" = '9c54986f-8284-4da9-b826-c7a723de279b';
Error: in prepare, no such column: companies.company_id (1)
Есть ли способ решить эту проблему, воздействуя на конфигурацию Laravel или SQLite? Я не могу изменить способ генерации запросов, поскольку они генерируются самой платформой.
Кроме того, я НЕ спрашиваю, почему этот конкретный запрос ведет себя именно так, это мне уже было ясно.
Фрагмент and "company_id" = '9c54986f-8284-4da9-b826-c7a723de279b' генерируется глобальной областью видимости, реализованной следующим образом:
abstract readonly class UnlessAuthorizedScope implements Scope {
public function __construct(
private string $modelField,
protected ?string $authorizingPermission,
private string $userField,
) {}
public function apply(Builder $builder, Model $model): void {
if (Auth::hasUser()) {
$user = Auth::user();
if (
!$this->authorizingPermission
|| !$user?->can($this->authorizingPermission)
) {
$builder->where(
$this->modelField,
$user?->{$this->userField}
);
}
}
}
}
который затем реализуется в:
readonly class CurrentCompanyScope extends UnlessAuthorizedScope {
public function __construct(?string $authorizingPermission = null, ?string $modelField = null) {
parent::__construct(
$modelField ?? "company_id",
$authorizingPermission,
"company_id"
);
}
}
и, наконец, используется как:
class Company extends Model {
protected static function booted(): void {
parent::booted();
static::addGlobalScope(new CurrentCompanyScope(
CompanyPermission::ViewAll->value,
// the error was here, instead of specifying "id", I kept the default "company_id" value
));
}
}
Да, в этом конкретном случае, но мне также хотелось бы найти способ сделать это так, чтобы он выдавал мне ошибку, а не молча выходил из строя, если я снова совершу подобную ошибку.
Кстати, Laravel, скорее всего, заключает столбцы в двойные кавычки на случай, если вы используете ключевое слово в качестве идентификатора. Поэтому, если Laravel перестанет это делать, хотя это решит вашу проблему, это может создать другие проблемы.
Да, я так и предполагал, но мне хотелось бы знать, есть ли решение этой проблемы без потери функциональности фреймворка... У меня просто возникла идея, которую я мог бы попробовать.
Примечание. Я отменил ваш вопрос, недавнее изменение которого сделало мой ответ недействительным. Не меняйте свой вопрос, включив в него мой ответ.
Я понятия не имею, о чем вы говорите, поскольку я просто показал, КАК был сгенерирован запрос; Кроме того, из-за вашего неправильного редактирования мой собственный ответ потерял контекст, поэтому я восстановлю его.






Я думаю, что здесь происходит то, что "company_id" интерпретируется как строковый литерал, а не как столбец. Имейте в виду, что SQLite принимает строковые литералы как в одинарных, так и в двойных кавычках. Судя по всему, эвристика SQLite для интерпретации строк в двойных кавычках такова:
Вот ваш запрос еще раз в формате:
SELECT *
FROM "companies"
WHERE
"companies"."id" = '9c54986f-8284-4da9-b826-c7a723de279b' AND
"companies"."deleted_at" IS NULL AND
"company_id" = '9c54986f-8284-4da9-b826-c7a723de279b';
Поскольку столбец company_id не существует, этот запрос интерпретируется как:
SELECT *
FROM "companies"
WHERE
"companies"."id" = '9c54986f-8284-4da9-b826-c7a723de279b' AND
"companies"."deleted_at" IS NULL AND
'company_id' = '9c54986f-8284-4da9-b826-c7a723de279b';
Конечно, сравнение строк в последнем члене предложения WHERE никогда не будет истинным, поэтому никакие записи не возвращаются.
Нет необходимости заключать столбцы в двойные кавычки, поэтому не используйте их, чтобы избежать проблем такого рода.
RE There is no need for your columns to be in double quotes, so don't use them, to avoid this sort of problem.: как сказано в моем вопросе, я не могу изменить способ генерации запросов, поскольку они генерируются самой платформой.
@MatteoTassinari Тогда фреймворк не имеет смысла, если он добавляет случайные столбцы в ваше предложение WHERE. Более вероятно, что ваш код Laravel каким-то образом ссылается на столбец company_id.
@MatteoTassinari Ну, в любом случае, ваш вопрос был бы намного понятнее, если бы он содержал код, сгенерировавший ваш запрос.
Примечание. Это был ответ на исходный вопрос. Впоследствии пользователь изменил вопрос, включив в него мой ответ.
Не могли бы вы объяснить, что вы подразумеваете под «включением моего ответа»? То есть я не понимаю, какие части Вашего ответа я бы "включил"? На самом деле, это не риторика, я хотел бы понять, сделал ли я что-то не так, а английский не является моим основным языком, поэтому в этом моя трудность.
@TimBiegeleisen Я перечитал ваш ответ, и если вы чувствуете, что я «включил» ту часть, где вы это говорите What I think is happening here is that "company_id" is being interpreted as a string literal, rather than a column., я хотел бы отметить, что такой вывод уже был в моей самой первой редакции; кроме этого, остальная часть вашего ответа никоим образом не присутствует в моем вопросе.
RE: Then the framework makes little sense if it adds random columns to your WHERE clause., я никогда не утверждал, что это «случайно», я знаю, почему этот фрагмент запроса был там, и я исправил источник этой конкретной ошибки, которая не является сутью вопроса.
Мне удалось решить эту проблему, изменив реализацию моей базовой глобальной области:
abstract readonly class UnlessAuthorizedScope implements Scope {
public function __construct(
private string $modelField,
protected ?string $authorizingPermission,
private string $userField,
) {}
public function apply(Builder $builder, Model $model): void {
if (Auth::hasUser()) {
$user = Auth::user();
if (
!$this->authorizingPermission
|| !$user?->can($this->authorizingPermission)
) {
$builder->where(
$model->getTable().".".$this->modelField, // changed here
$user?->{$this->userField}
);
}
}
}
}
добавив явный префикс таблицы к имени поля, он сохранялся в запросе, сгенерированном платформой, который затем стал:
select * from "companies" where "companies"."id" = '9c54986f-8284-4da9-b826-c7a723de279b' and "companies"."deleted_at" is null and "companies"."compa
ny_id" = '9c54986f-8284-4da9-b826-c7a723de279b'
и этот новый запрос сгенерировал правильное исключение, которое было перехвачено платформой и отображено на странице.
the error was here... так вы уже исправили проблему в своем коде Laravel?