1 | <?php |
||
29 | trait ImportableAdminTrait |
||
30 | { |
||
31 | /** |
||
32 | * Options to set to the form (ie, validation_groups). |
||
33 | * |
||
34 | * @var array |
||
35 | */ |
||
36 | protected $formOptions = []; |
||
37 | /** |
||
38 | * @var Form |
||
39 | */ |
||
40 | private $importForm; |
||
41 | |||
42 | /** |
||
43 | * {@inheritdoc} |
||
44 | */ |
||
45 | abstract public function getClass(); |
||
46 | |||
47 | /** |
||
48 | * @return Pool |
||
49 | */ |
||
50 | abstract public function getConfigurationPool(); |
||
51 | |||
52 | /** |
||
53 | * @return FormContractorInterface |
||
54 | */ |
||
55 | abstract public function getFormContractor(); |
||
56 | |||
57 | /** |
||
58 | * {@inheritdoc} |
||
59 | * |
||
60 | * @throws \ReflectionException |
||
61 | */ |
||
62 | public function getImportFormBuilder(array $headers) |
||
63 | { |
||
64 | $class = $this->hasActiveSubClass() ? $this->getActiveSubClass() : $this->getClass(); |
||
65 | if ((new \ReflectionClass($class))->isAbstract()) { |
||
66 | // If $class is Abstract, then use the first one. |
||
67 | // Developers should then instantiate the good class by overriding DoctrineWrite::writeItem() |
||
68 | $class = array_values($this->getSubClasses())[0]; |
||
69 | } |
||
70 | |||
71 | $this->formOptions['data_class'] = $class; |
||
72 | |||
73 | $formBuilder = $this->getFormContractor()->getFormBuilder( |
||
74 | 'import_form', $this->formOptions |
||
75 | ); |
||
76 | |||
77 | $this->defineImportFormBuilder($formBuilder, $headers); |
||
78 | |||
79 | return $formBuilder; |
||
80 | } |
||
81 | |||
82 | /** |
||
83 | * @param FormBuilderInterface $formBuilder |
||
84 | * @param array $headers |
||
85 | * todo: use defineFormBuilder for import Action and upload Action |
||
86 | */ |
||
87 | public function defineImportFormBuilder(FormBuilderInterface $formBuilder, array $headers) |
||
88 | { |
||
89 | /** @var AbstractAdmin $this */ |
||
90 | $mapper = new FormMapper($this->getFormContractor(), $formBuilder, $this); |
||
91 | $this->configureImportFields($mapper); |
||
92 | /** @var ContainerInterface $container */ |
||
93 | $container = $this->getConfigurationPool()->getContainer(); |
||
94 | $trans = $container->get('translator'); |
||
95 | |||
96 | $oldValue = ini_get('mbstring.substitute_character'); |
||
97 | ini_set('mbstring.substitute_character', 'none'); |
||
98 | foreach ($formBuilder as $field) { |
||
99 | /* @var FormBuilder $field */ |
||
100 | if ($field->getType()->getInnerType() instanceof EntityType) { |
||
101 | continue; |
||
102 | } |
||
103 | $propertyPath = $field->getPropertyPath(); |
||
104 | if ($propertyPath && $propertyPath->getLength() > 1) { |
||
105 | $mapper->add( |
||
106 | (string) $propertyPath, ImportFieldChoiceType::class, [ |
||
107 | 'choices' => $headers, |
||
108 | 'data' => $this->nearest($field->getOption('label'), $headers, $trans), |
||
109 | 'mapped' => false, |
||
110 | 'label' => $field->getOption('label'), |
||
111 | ]); |
||
112 | } elseif ('id' === (string) $propertyPath) { |
||
113 | $mapper->add($field->getName(), ImportFieldChoiceType::class, [ |
||
114 | 'choices' => $headers, |
||
115 | 'data' => $this->nearest($field->getOption('label'), $headers, $trans), |
||
116 | 'mapped' => false, |
||
117 | 'label' => $field->getOption('label'), |
||
118 | ]); |
||
119 | } else { |
||
120 | $mapper->add($field->getName(), ImportFieldChoiceType::class, [ |
||
121 | 'choices' => $headers, |
||
122 | 'data' => $this->nearest($field->getOption('label'), $headers, $trans, $field->getOption('translation_domain')), |
||
123 | 'mapped' => $field->getOption('mapped'), |
||
124 | 'label' => $field->getOption('label'), |
||
125 | 'label_format' => $field->getOption('label_format'), // This will be used for DateTimeConverter |
||
126 | 'translation_domain' => $field->getOption('translation_domain'), |
||
127 | ]); |
||
128 | } |
||
129 | } |
||
130 | ini_set('mbstring.substitute_character', $oldValue); |
||
131 | $formBuilder->add('import', SubmitType::class); |
||
132 | $this->attachInlineValidator(); |
||
133 | } |
||
134 | |||
135 | /** |
||
136 | * @param $admin |
||
137 | * @param null $object |
||
138 | * |
||
139 | * @return mixed |
||
140 | */ |
||
141 | public function configureActionButtons($admin, $object = null) |
||
149 | |||
150 | /** |
||
151 | * @param array $headers |
||
152 | * |
||
153 | * @throws \ReflectionException |
||
154 | * |
||
155 | * @return Form |
||
156 | */ |
||
157 | public function getImportForm(array $headers) |
||
163 | |||
164 | /** |
||
165 | * @param StepAggregator $workflow |
||
166 | */ |
||
167 | public function configureImportSteps(StepAggregator $workflow) |
||
185 | |||
186 | /** |
||
187 | * This method can be overloaded in your Admin service. |
||
188 | * It's called from importAction. |
||
189 | * |
||
190 | * @param Request $request |
||
191 | * @param Form $form |
||
192 | * |
||
193 | * @return Response|null |
||
194 | */ |
||
195 | public function preImport(Request $request, Form $form) |
||
198 | |||
199 | /** |
||
200 | * This method can be overloaded in your Admin service. |
||
201 | * It's called from importAction. |
||
202 | * |
||
203 | * @param Request $request |
||
204 | * @param UploadedFile $file |
||
205 | * @param Form $form |
||
206 | * @param mixed $results |
||
207 | * |
||
208 | * @return Response|null |
||
209 | */ |
||
210 | public function postImport(Request $request, UploadedFile $file, Form $form, $results) |
||
213 | |||
214 | /** |
||
215 | * @param FormMapper $formMapper |
||
216 | */ |
||
217 | abstract protected function configureImportFields(FormMapper $formMapper); |
||
218 | |||
219 | /** |
||
220 | * Attach the inline validator to the model metadata, this must be done once per admin. |
||
221 | */ |
||
222 | abstract protected function attachInlineValidator(); |
||
223 | |||
224 | /** |
||
225 | * @param RouteCollection $collection |
||
226 | */ |
||
227 | protected function configureRoutes(RouteCollection $collection) |
||
235 | |||
236 | /** |
||
237 | * @param array $headers |
||
238 | * |
||
239 | * @throws \ReflectionException |
||
240 | */ |
||
241 | protected function buildImportForm(array $headers) |
||
248 | |||
249 | /** |
||
250 | * @param $input |
||
251 | * @param $words |
||
252 | * @param TranslatorInterface $trans |
||
253 | * @param string $domain |
||
254 | * |
||
255 | * @return string |
||
256 | */ |
||
257 | private function nearest($input, $words, TranslatorInterface $trans, $domain = null) |
||
282 | } |
||
283 |
This check looks for methods that are used by a trait but not required by it.
To illustrate, let’s look at the following code example
The trait
Idable
provides a methodequalsId
that in turn relies on the methodgetId()
. If this method does not exist on a class mixing in this trait, the method will fail.Adding the
getId()
as an abstract method to the trait will make sure it is available.