Further modules included.
[yaffs-website] / web / modules / contrib / filefield_sources / src / Plugin / FilefieldSource / Reference.php
1 <?php
2
3 /**
4  * @file
5  * Contains \Drupal\filefield_sources\Plugin\FilefieldSource\Reference.
6  */
7
8 namespace Drupal\filefield_sources\Plugin\FilefieldSource;
9
10 use Drupal\Core\Form\FormStateInterface;
11 use Drupal\filefield_sources\FilefieldSourceInterface;
12 use Symfony\Component\Routing\Route;
13 use Drupal\Core\Field\WidgetInterface;
14 use Symfony\Component\HttpFoundation\JsonResponse;
15 use Symfony\Component\HttpFoundation\Request;
16 use Drupal\Component\Utility\Unicode;
17 use Drupal\Component\Utility\Html;
18
19 /**
20  * A FileField source plugin to allow referencing of existing files.
21  *
22  * @FilefieldSource(
23  *   id = "reference",
24  *   name = @Translation("Autocomplete reference textfield"),
25  *   label = @Translation("Reference existing"),
26  *   description = @Translation("Reuse an existing file by entering its file name."),
27  *   weight = 1
28  * )
29  */
30 class Reference implements FilefieldSourceInterface {
31
32   /**
33    * {@inheritdoc}
34    */
35   public static function value(array &$element, &$input, FormStateInterface $form_state) {
36     if (isset($input['filefield_reference']['autocomplete']) && strlen($input['filefield_reference']['autocomplete']) > 0 && $input['filefield_reference']['autocomplete'] != FILEFIELD_SOURCE_REFERENCE_HINT_TEXT) {
37       $matches = array();
38       if (preg_match('/\[fid:(\d+)\]/', $input['filefield_reference']['autocomplete'], $matches)) {
39         $fid = $matches[1];
40         if ($file = file_load($fid)) {
41
42           // Remove file size restrictions, since the file already exists on
43           // disk.
44           if (isset($element['#upload_validators']['file_validate_size'])) {
45             unset($element['#upload_validators']['file_validate_size']);
46           }
47
48           // Check that the user has access to this file through
49           // hook_download().
50           if (!$file->access('download')) {
51             $form_state->setError($element, t('You do not have permission to use the selected file.'));
52           }
53           elseif (filefield_sources_element_validate($element, (object) $file, $form_state)) {
54             if (!in_array($file->id(), $input['fids'])) {
55               $input['fids'][] = $file->id();
56             }
57           }
58         }
59         else {
60           $form_state->setError($element, t('The referenced file could not be used because the file does not exist in the database.'));
61         }
62       }
63       // No matter what happens, clear the value from the autocomplete.
64       $input['filefield_reference']['autocomplete'] = '';
65     }
66   }
67
68   /**
69    * {@inheritdoc}
70    */
71   public static function process(array &$element, FormStateInterface $form_state, array &$complete_form) {
72
73     $element['filefield_reference'] = array(
74       '#weight' => 100.5,
75       '#theme' => 'filefield_sources_element',
76       '#source_id' => 'reference',
77       // Required for proper theming.
78       '#filefield_source' => TRUE,
79       '#filefield_sources_hint_text' => FILEFIELD_SOURCE_REFERENCE_HINT_TEXT,
80     );
81
82     $autocomplete_route_parameters = array(
83       'entity_type' => $element['#entity_type'],
84       'bundle_name' => $element['#bundle'],
85       'field_name' => $element['#field_name'],
86     );
87
88     $element['filefield_reference']['autocomplete'] = array(
89       '#type' => 'textfield',
90       '#autocomplete_route_name' => 'filefield_sources.autocomplete',
91       '#autocomplete_route_parameters' => $autocomplete_route_parameters,
92       '#description' => filefield_sources_element_validation_help($element['#upload_validators']),
93     );
94
95     $class = '\Drupal\file\Element\ManagedFile';
96     $ajax_settings = [
97       'callback' => [$class, 'uploadAjaxCallback'],
98       'options' => [
99         'query' => [
100           'element_parents' => implode('/', $element['#array_parents']),
101         ],
102       ],
103       'wrapper' => $element['upload_button']['#ajax']['wrapper'],
104       'effect' => 'fade',
105     ];
106
107     $element['filefield_reference']['select'] = [
108       '#name' => implode('_', $element['#parents']) . '_autocomplete_select',
109       '#type' => 'submit',
110       '#value' => t('Select'),
111       '#validate' => [],
112       '#submit' => ['filefield_sources_field_submit'],
113       '#limit_validation_errors' => [$element['#parents']],
114       '#ajax' => $ajax_settings,
115     ];
116
117     return $element;
118   }
119
120   /**
121    * Theme the output of the reference element.
122    */
123   public static function element($variables) {
124     $element = $variables['element'];
125
126     $element['autocomplete']['#field_suffix'] = drupal_render($element['select']);
127     return '<div class="filefield-source filefield-source-reference clear-block">' . drupal_render($element['autocomplete']) . '</div>';
128   }
129
130   /**
131    * Menu callback; autocomplete.js callback to return a list of files.
132    */
133   public static function autocomplete(Request $request, $entity_type, $bundle_name, $field_name) {
134     $matches = array();
135     $string = Unicode::strtolower($request->query->get('q'));
136
137     if (isset($string)) {
138       $widget = entity_get_form_display($entity_type, $bundle_name, 'default')->getComponent($field_name);
139       if ($widget) {
140         // // If we are looking at a single field, cache its settings, in case we want to search all fields.
141         $setting_autocomplete = $widget['third_party_settings']['filefield_sources']['filefield_sources']['source_reference']['autocomplete'];
142         $setting_search_all_fields = $widget['third_party_settings']['filefield_sources']['filefield_sources']['source_reference']['search_all_fields'];
143       }
144
145       $field_definition = entity_load('field_config', $entity_type . '.' . $bundle_name . '.' . $field_name);
146       if (!isset($field_definition) || $setting_search_all_fields) {
147         $field_definitions = \Drupal::entityManager()->getStorage('field_config')->loadByProperties(array('type' => array('file', 'image')));
148       }
149       else {
150         $field_definitions = array($field_definition);
151       }
152
153       foreach ($field_definitions as $field_definition) {
154         $handler = \Drupal::getContainer()->get('plugin.manager.entity_reference_selection')->getSelectionHandler($field_definition);
155
156         // If we are searching all fields, use the autocomplete settings from the source field.
157         $match_operator = empty($setting_autocomplete) ? 'STARTS_WITH' : 'CONTAINS';
158         // Get an array of matching entities.
159         $entity_labels = $handler->getReferenceableEntities($string, $match_operator, 10);
160
161         // Loop through the entities and convert them into autocomplete output.
162         foreach ($entity_labels as $values) {
163           foreach ($values as $entity_id => $label) {
164             $key = "$label [fid:$entity_id]";
165             // Strip things like starting/trailing white spaces, line breaks and
166             // tags.
167             $key = preg_replace('/\s\s+/', ' ', str_replace("\n", '', trim(Html::decodeEntities(strip_tags($key)))));
168             // Names containing commas or quotes must be wrapped in quotes.
169             $matches[] = array('value' => $key, 'label' => $label);
170           }
171         }
172       }
173     }
174
175     return new JsonResponse($matches);
176   }
177
178   /**
179    * Define routes for Reference source.
180    *
181    * @return array
182    *   Array of routes.
183    */
184   public static function routes() {
185     $routes = array();
186
187     $routes['filefield_sources.autocomplete'] = new Route(
188       '/file/reference/{entity_type}/{bundle_name}/{field_name}',
189       array(
190         '_controller' => get_called_class() . '::autocomplete',
191       ),
192       array(
193         '_access_filefield_sources_field' => 'TRUE',
194       )
195     );
196
197     return $routes;
198   }
199
200   /**
201    * Implements hook_filefield_source_settings().
202    */
203   public static function settings(WidgetInterface $plugin) {
204     $settings = $plugin->getThirdPartySetting('filefield_sources', 'filefield_sources', array(
205       'source_reference' => array(
206         'autocomplete' => FILEFIELD_SOURCE_REFERENCE_MATCH_STARTS_WITH,
207         'search_all_fields' => FILEFIELD_SOURCE_REFERENCE_SEARCH_ALL_NO,
208       ),
209     ));
210
211     $return['source_reference'] = array(
212       '#title' => t('Autocomplete reference options'),
213       '#type' => 'details',
214     );
215
216     $return['source_reference']['autocomplete'] = array(
217       '#title' => t('Match file name'),
218       '#options' => array(
219         FILEFIELD_SOURCE_REFERENCE_MATCH_STARTS_WITH => t('Starts with'),
220         FILEFIELD_SOURCE_REFERENCE_MATCH_CONTAINS => t('Contains'),
221       ),
222       '#type' => 'radios',
223       '#default_value' => isset($settings['source_reference']['autocomplete']) ? $settings['source_reference']['autocomplete'] : FILEFIELD_SOURCE_REFERENCE_MATCH_STARTS_WITH,
224     );
225
226     $return['source_reference']['search_all_fields'] = array(
227       '#title' => t('Search all file fields'),
228       '#options' => array(
229         FILEFIELD_SOURCE_REFERENCE_SEARCH_ALL_NO => t('No (only fields with the same field base will be searched)'),
230         FILEFIELD_SOURCE_REFERENCE_SEARCH_ALL_YES => t('Yes (all file fields will be searched, regardless of type)'),
231       ),
232       '#type' => 'radios',
233       '#default_value' => isset($settings['source_reference']['search_all_fields']) ? $settings['source_reference']['search_all_fields'] : FILEFIELD_SOURCE_REFERENCE_SEARCH_ALL_NO,
234      );
235
236     return $return;
237   }
238
239 }