để đối phó với các giá trị tự động thêm vào sử dụng 'choice_loader'
tùy chọn kiểu lựa chọn. It's new in symfony 2.7 và đáng tiếc là không có bất kỳ tài liệu nào cả.
Về cơ bản nó là một dịch vụ thực hiện ChoiceLoaderInterface
trong đó xác định ba chức năng:
loadValuesForChoices(array $choices, $value = null)
- được kêu gọi xây dựng hình thức và nhận các giá trị cài đặt trước của đối tượng bị ràng buộc vào mẫu
loadChoiceList($value = null)
- được kêu gọi xây dựng quan điểm và phải trả lại toàn bộ danh sách các lựa chọn nói chung
loadChoicesForValues(array $values, $value = null)
- được gọi vào mẫu nộp và nhận dữ liệu gửi
Bây giờ ý tưởng là giữ ArrayChoiceList
là thuộc tính riêng tư trong bộ chọn lựa. Trên hình thức xây dựng loadValuesForChoices(...)
được gọi, ở đây chúng tôi thêm tất cả các lựa chọn đặt trước vào danh sách lựa chọn của chúng tôi để chúng có thể được hiển thị cho người dùng. Trên chế độ xem xây dựng, loadChoiceList(...)
được gọi, nhưng chúng tôi không tải bất cứ thứ gì, chúng tôi chỉ trả lại danh sách lựa chọn riêng tư của chúng tôi được tạo trước đó.
Bây giờ người dùng tương tác với biểu mẫu, một số lựa chọn bổ sung được tải thông qua tính năng tự động hoàn tất và được đưa vào HTML thứ. Khi gửi biểu mẫu, các giá trị đã chọn được gửi và trong hành động điều khiển của chúng tôi trước tiên, biểu mẫu được tạo và sau đó, $form->handleRequest(..)
loadChoicesForValues(...)
được gọi, nhưng các giá trị đã gửi có thể hoàn toàn khác với các giá trị được bao gồm trong phần đầu.Vì vậy, chúng tôi thay thế danh sách lựa chọn nội bộ của chúng tôi bằng một danh sách mới chỉ chứa các giá trị đã gửi.
Biểu mẫu của chúng tôi giờ đây hoàn toàn giữ dữ liệu được thêm bằng tự động hoàn thành.
Phần khó khăn là, chúng ta cần một phiên bản mới của trình chọn lựa chọn của chúng tôi bất cứ khi nào chúng tôi sử dụng loại biểu mẫu, nếu không danh sách lựa chọn nội bộ sẽ chứa hỗn hợp của tất cả các lựa chọn.
Vì mục tiêu là viết loại lựa chọn tự động hoàn thành mới, bạn thường sử dụng tính năng tiêm phụ thuộc để chuyển bộ chọn lựa của bạn vào dịch vụ kiểu. Nhưng đối với các loại này, điều này là không thể nếu bạn luôn cần một phiên bản mới, thay vào đó chúng tôi phải bao gồm nó thông qua các tùy chọn. Việc đặt trình chọn lựa chọn trong các tùy chọn mặc định sẽ không hoạt động, vì chúng cũng được lưu trữ. Để giải quyết vấn đề mà bạn phải viết một hàm nặc danh mà cần phải lấy các tùy chọn như các thông số:
$resolver->setDefaults(array(
'choice_loader' => function (Options $options) {
return AutocompleteFactory::createChoiceLoader();
},
));
Edit: Đây là một phiên bản thu gọn của lớp lựa chọn bộ nạp:
use Symfony\Component\Form\ChoiceList\ArrayChoiceList;
use Symfony\Component\Form\ChoiceList\ChoiceListInterface;
use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface;
class AutocompleteChoiceLoader implements ChoiceLoaderInterface
{
/** @var ChoiceListInterface */
private $choiceList;
public function loadValuesForChoices(array $choices, $value = null)
{
// is called on form creat with $choices containing the preset of the bound entity
$values = array();
foreach ($choices as $key => $choice) {
// we use a DataTransformer, thus only plain values arrive as choices which can be used directly as value
if (is_callable($value)) {
$values[$key] = (string)call_user_func($value, $choice, $key);
}
else {
$values[$key] = $choice;
}
}
// this has to be done by yourself: array(label => value)
$labeledValues = MyLabelService::getLabels($values);
// create internal choice list from loaded values
$this->choiceList = new ArrayChoiceList($labeledValues, $value);
return $values;
}
public function loadChoiceList($value = null)
{
// is called on form view create after loadValuesForChoices of form create
if ($this->choiceList instanceof ChoiceListInterface) {
return $this->choiceList;
}
// if no values preset yet return empty list
$this->choiceList = new ArrayChoiceList(array(), $value);
return $this->choiceList;
}
public function loadChoicesForValues(array $values, $value = null)
{
// is called on form submit after loadValuesForChoices of form create and loadChoiceList of form view create
$choices = array();
foreach ($values as $key => $val) {
// we use a DataTransformer, thus only plain values arrive as choices which can be used directly as value
if (is_callable($value)) {
$choices[$key] = (string)call_user_func($value, $val, $key);
}
else {
$choices[$key] = $val;
}
}
// this has to be done by yourself: array(label => value)
$labeledValues = MyLabelService::getLabels($values);
// reset internal choice list
$this->choiceList = new ArrayChoiceList($labeledValues, $value);
return $choices;
}
}
Ồ, nếu chỉ tôi biết những gì các phím mảng và giá trị nên được! –
@IanPhillips tùy thuộc vào mảng bạn muốn nói. Đối với các giá trị trả về của các hàm, hãy xem phpDoc của 'ChoiceLoaderInterface'. Các khóa luôn nằm trong mảng tham số và giá trị hoặc là các lựa chọn hoặc giá trị. Lưu ý rằng bạn vẫn cần một [DataTransformer] (http://symfony.com/doc/current/cookbook/form/data_transformers.html) nếu bạn làm việc với các thực thể! Mảng được sử dụng để tạo 'ArrayChoiceList' nội bộ phải chứa các nhãn'
@IanPhillips Tôi đã thêm phiên bản rút gọn của trình tải lựa chọn tự động hoàn thành – SBH