Наблюдаю странное поведение при выборке.
Данные выбираются из таблицы 'article', по колонке 'tag_id' (статьи, у которых есть нужный тег)
ID тегов хранится как отдельное число или как числа, перечисленные через запятую '1,5,10' или '10' или '19,14'
Реализация в модели:
class Tags extends Model {
use HasFactory;
protected $table = 'tags';
public function getArticleWithTags() {
return Article::where('tag_id', $this->id)
->orWhere('tag_id', 'like', $this->id.',%')
->orWhere('tag_id', 'like', '%,'.$this->id)
->orWhere('tag_id', 'like', '%,'.$this->id.',%')
->get();
}
}
Запятую нужно учитывать, для исключения однозначных вхождений в двухзначные, т.е. если использовать where('tag_id', 'like', '%'.$this->id.'%'), то при поиске id=5, в выборку так же попадут id=15,25,51, etc.
Но что то пошло не так...
При нормальном поведении в результаты запроса 'tags.id'='article.tag_id':
public function getArticleWithTags() {
return Article::where('tag_id', '=', $this->id)->dd();
//->get();
}
должны попадать данные с точным соответствием id из двух колонок.
Т.е. из запроса выше select * from 'article' where 'tag_id' = 1 должны вернуться строки из таблицы, где в колонке tag_id стоит 1
Но в выбокру так же попадают значения, у которых в колонке tag_id стоят следующие значения: '1', '1,11', '1,9', '1,Z', '1,qwerty', '1qwerty' при этом, как и положено, игнорируются: '9,1', '19', 'abc,1'.
Условие where('tag_id', $this->id) можно заменить на where('tag_id', 'like', $this->id)
Получив корректную работу:
return Article::where('tag_id', 'like', $this->id)
->orWhere('tag_id', 'like', $this->id.',%')
->orWhere('tag_id', 'like', '%,'.$this->id)
->orWhere('tag_id', 'like', '%,'.$this->id.',%')
->get();
}
Так же, конструкция where('tag_id', $this->id) будет корректно работать, если приводить передаваемый аргумент к строке:
return Article::where('tag_id', ''.$this->id)->get();
return Article::where('tag_id', (string)$this->id)->get();
return Article::where('tag_id', strval($this->id))->get();
Но вопросы остались...
Почему без приведения к строке попадают в выборку странные значения?
Типы колонок:
- tags.id - bigint(20)
- article.tag_id - varchar(255)
Получается сравнение идёт по первому символу
select * from 'article' where [varchar(255)='1qwerty'] = [bigint(20)=1]
Точнее из двух сравниваемых значений именно varchar приводится к числу, иначе (при приведении искомого id к строке) и результаты бы такие не появлялись и ручного приведения делать не пришлось бы, да и при явном приведении лишние данные из выборки пропадают
По итогу из varchar берётся первый символ, который видимо преобразуется в число. Или первый символ сравнивается после такой обрезки с id, преобразованным в строку, но тогда почему id не приводится к строке на более раннем этапе.
Для меня странно такое преобразование В документации не видел комментариев по такому поведению.
Какие мысли? Что посмотреть по теме? Буду признателен...

