У меня есть следующий сценарий.
Программное обеспечение: Current CakePHP 4 Beta (Commit 48c3f80f8f)
SQL для таблиц
Позволяет изображению иметь 2 таблицы.
DROP TABLE IF EXISTS customers;
CREATE TABLE customers
(
id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
company VARCHAR(255),
first_name VARCHAR(255),
last_name VARCHAR(255),
created DATETIME DEFAULT CURRENT_TIMESTAMP,
modified DATETIME DEFAULT CURRENT_TIMESTAMP
) CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
DROP TABLE IF EXISTS customers_contacts;
CREATE TABLE customers_contacts
(
id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
company VARCHAR(255),
first_name VARCHAR(255),
last_name VARCHAR(255),
customers_id INT UNSIGNED NOT NULL,
created DATETIME DEFAULT CURRENT_TIMESTAMP,
modified DATETIME DEFAULT CURRENT_TIMESTAMP
) CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
И поэтому у нас есть связь один-ко-многим между клиентами и клиентами_контакты
// CustomersTable.php
$this->hasMany( 'CustomersContacts', [
'foreignKey' => 'customers_id'
] );
// CustomersContactsTable.php
$this->belongsTo( 'Customers', [
'foreignKey' => 'customers_id'
] );
Реализация поиска
Первым шагом было внедрение поиска, где я могуне только поиск значений одного столбца, но также и связанных столбцов, таких как «имя, фамилия» или «имя, фамилия»
Это работает
Я выполнил это с помощью следующего кода внутри моей индексной функции
$query = $this->Customers->find( 'all' )
->contain( ['CustomersContacts'] );
$current_request = $this->getRequest();
$search = $current_request->getQuery( 'search' );
// Default cake sort by clicking on table head
$sort_dir = $current_request->getQuery( 'direction' );
$sort_col = $current_request->getQuery( 'sort' );
if ( $current_request->is( 'get' ) ) {
// Default sort by modified date
if ( $sort_dir == '' && $sort_col == '' ) {
$query->orderDesc( 'Customers.modified' );
}
// Change query if a search parameter is given in GET data
if ( $search ) {
// Search for concat fields in cakephp >=3
// https://stackoverflow.com/questions/35405261/search-with-concat-fields-in-cakephp-3
$query->where( function( $exp, $q ) use ( $search ) {
/**
* @var QueryExpression $exp
* @var Query $q
*/
// Concatenated Customers Name
$conc1 = $q->func()
->concat( [
'Customers.first_name' => 'literal',
' ',
'Customers.last_name' => 'literal'
] );
$conc2 = $q->func()
->concat( [
'Customers.last_name' => 'literal',
' ',
'Customers.first_name' => 'literal'
] );
return $exp->or( [
'Customers.company LIKE' => "%$search%",
'Customers.first_name LIKE' => "%$search%",
'Customers.last_name LIKE' => "%$search%",
] )
->like( $conc1, "%$search%" )
->like( $conc2, "%$search%" );
} );
$current_request = $current_request->withData( 'search', $search );
$this->setRequest( $current_request );
}
}
$Customers = $this->paginate( $query );
$this->set( compact( 'Customers' ) );
Это не работает
Тогда я подумал, что могу улучшить поиск, добавив также имя и фамилию таблицы контактов подключенных клиентов со следующим кодом:
$query = $this->Customers->find( 'all' )
->contain( ['CustomersContacts'] );
$current_request = $this->getRequest();
$search = $current_request->getQuery( 'search' );
// Default cake sort by clicking on table head
$sort_dir = $current_request->getQuery( 'direction' );
$sort_col = $current_request->getQuery( 'sort' );
if ( $current_request->is( 'get' ) ) {
// Default sort by modified date
if ( $sort_dir == '' && $sort_col == '' ) {
$query->orderDesc( 'Customers.modified' );
}
// Change query if a search parameter is given in GET data
if ( $search ) {
// Search for concat fields in cakephp >=3
// https://stackoverflow.com/questions/35405261/search-with-concat-fields-in-cakephp-3
$query->where( function( $exp, $q ) use ( $search ) {
/**
* @var QueryExpression $exp
* @var Query $q
*/
// Concatenated Customers Name
$conc1 = $q->func()
->concat( [
'Customers.first_name' => 'literal',
' ',
'Customers.last_name' => 'literal'
] );
$conc2 = $q->func()
->concat( [
'Customers.last_name' => 'literal',
' ',
'Customers.first_name' => 'literal'
] );
// Concatenated CustomersContacts Name
$conc3 = $q->func()
->concat( [
'CustomersContacts.first_name' => 'literal',
' ',
'CustomersContacts.last_name' => 'literal'
] );
$conc4 = $q->func()
->concat( [
'CustomersContacts.last_name' => 'literal',
' ',
'CustomersContacts.first_name' => 'literal'
] );
return $exp->or( [
'Customers.company LIKE' => "%$search%",
'Customers.first_name LIKE' => "%$search%",
'Customers.last_name LIKE' => "%$search%",
'CustomersContacts.first_name LIKE' => "%$search%",
'CustomersContacts.last_name LIKE' => "%$search%"
] )
->like( $conc1, "%$search%" )
->like( $conc2, "%$search%" )
->like( $conc3, "%$search%" )
->like( $conc4, "%$search%" );
} );
$current_request = $current_request->withData( 'search', $search );
$this->setRequest( $current_request );
}
}
$Customers = $this->paginate( $query );
$this->set( compact( 'Customers' ) );
Ошибка
Но теперь, когда я выполняю поиск, я получаю следующую ошибку:
Column not found: 1054 Unknown column 'CustomersContacts.first_name' in 'where clause'
Что я на самом деле не получаю, потому что соединение между клиентамии CustomersContacts должны были произойти с
->contain( ['CustomersContacts'] );
Но, похоже, это не так, потому что в Debug Kit я проверил SQL-запрос, и нет соединения между Contacts и ContactsCustomers.
Что я ожидаю
Таким образом, ожидаемый результат - показать всех клиентов, у которых есть связанные контакты с клиентами, где данный поисковый запрос имеет отношение к имени или фамилии этих контактов с клиентами.
Возможно ли это при таком подходе или мне нужно пойти другим путем?