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]);