CakePHP 3 autocomplete
W poprzednich dwóch częściach omawialiśmy dodawanie powiązanych rekordów. Ale co jeśli chcesz wybrać rekord z powiązanej tabeli, w której znajdują się tysiące rekordów? Funkcja autouzupełniania może pomóc w rozwiązaniu tego problemu. W kontrolerze użytkowników (src/Controller/UsersController.php) utwórz funkcję, która zwraca listę rekordów w formacie json na podstawie danych wejściowych do pola formularza.
public function getAll()
{
if ($this->requrest->is('ajax')) {
$this->autoRender = false;
$name = $this->request->query['term'];
$results = $this->Users->find('all', [
'conditions' => [ 'OR' => [
'first_name LIKE' => $name . '%',
'last_name LIKE' => $name . '%',
]]
]);
$resultsArr = [];
foreach ($results as $result) {
$resultsArr[] = ['label' => $result['full_name'], 'value' => $result['id']];
}
echo json_encode($resultsArr);
}
}
W sekcji nagłówkowej strony załącz jQuery i jQuery UI.
echo $this->Html->script('//code.jquery.com/jquery-1.10.2.js');
echo $this->Html->script('//code.jquery.com/ui/1.11.4/jquery-ui.js');
echo $this->Html->css('//code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css');
Następnie w akcjach add i edit PhoneNumbers (/src/Template/PhoneNumbers/add.ctp), dodajmy skrypt do wywołania metody autocomplete() jQuery, która z kolei wywołuje funkcję getAll()
pobierającą dane.
<?php use Cake\Routing\Router; ?>
...
echo $this->Form->input('user_id', ['type' => 'text']);
...
<script>
jQuery('#user-id').autocomplete({
source:'<?php echo Router::url(array('controller' => 'Users', 'action' => 'getAll')); ?>',
minLength: 3
});
</script>
Teraz, gdy zaczniesz wpisywać imię w polu user_id,
powinna pojawić się lista autouzupełniania umożliwiająca wybranie użytkownika z listy.
Jednak po wybraniu nazwy użytkownika z listy autouzupełniania w polu pojawi się identyfikator użytkownika.
Skorygujemy to w dalszej części tutoriala.
Checemy wybierać nazwę użytkownika z listy autouzupełniania, ale checemy zapisywać w bazie danych identyfikator użytkownika.
W powiązanym modelu, w naszym przypadku modelu numerów telefonów (/src/Model/Table/PhoneNumbersTable.php) dodajemy:
use Cake\Event\Event; use ArrayObject; use Cake\ORM\TableRegistry;Następnie skonstruujemy funkcję beforeMarshal(), aby pobrać dane wejściowe user->full_name i przekonwertować je na user->id.
public function beforeMarshal(Event $event, ArrayObject $data, ArrayObject $options)
{
if (isset($data['user_id'])) {
$users = TableRegistry::get('Users');
$query = $users->find()
->select(['id'])
->where(['full_name' => $data['user_id']])
->first();
$data['user_id'] = $query['id'];
}
}
I na koniec ustaw funkcję getAll() dla naszych użytkowników, aby używać full_name jako wartości oraz etykiety.
$resultsArr[] =['label' => $result['full_name'], 'value' => $result['full_name']];W tym momencie formularz umożliwia wybranie i wyświetlenie pełnej nazwy, ale po wczytaniu numeru telefonu do edycji nadal wyświetla identyfikator użytkownika. W kontrolerze numerów telefonów (/src/Controller/PhoneNumbersController.php) upewnij się, że po otrzymaniu numeru telefonu do edycji "zawiera" informacje o użytkowniku.
public function edit($id = null)
{
$phoneNumber = $this->PhoneNumbers->get($id, [
'contain' => ['Users']
]);
...
Następnie w widoku /src/Template/PhoneNumbers/edit.ctp ustaw żądaną wartość dla pola, przesłaniając wartość domyślną.
$this->Form->input('user_id', ['type' => 'text', 'value' => $phoneNumber->user->full_name]);
