Security update for Core, with self-updated composer
[yaffs-website] / web / core / modules / node / src / NodeForm.php
1 <?php
2
3 namespace Drupal\node;
4
5 use Drupal\Component\Datetime\TimeInterface;
6 use Drupal\Core\Entity\ContentEntityForm;
7 use Drupal\Core\Entity\EntityManagerInterface;
8 use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
9 use Drupal\Core\Form\FormStateInterface;
10 use Drupal\Core\Session\AccountInterface;
11 use Drupal\user\PrivateTempStoreFactory;
12 use Symfony\Component\DependencyInjection\ContainerInterface;
13
14 /**
15  * Form handler for the node edit forms.
16  */
17 class NodeForm extends ContentEntityForm {
18
19   /**
20    * The tempstore factory.
21    *
22    * @var \Drupal\user\PrivateTempStoreFactory
23    */
24   protected $tempStoreFactory;
25
26   /**
27    * The Current User object.
28    *
29    * @var \Drupal\Core\Session\AccountInterface
30    */
31   protected $currentUser;
32
33   /**
34    * Constructs a NodeForm object.
35    *
36    * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
37    *   The entity manager.
38    * @param \Drupal\user\PrivateTempStoreFactory $temp_store_factory
39    *   The factory for the temp store object.
40    * @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_type_bundle_info
41    *   The entity type bundle service.
42    * @param \Drupal\Component\Datetime\TimeInterface $time
43    *   The time service.
44    * @param \Drupal\Core\Session\AccountInterface $current_user
45    *   The current user.
46    */
47   public function __construct(EntityManagerInterface $entity_manager, PrivateTempStoreFactory $temp_store_factory, EntityTypeBundleInfoInterface $entity_type_bundle_info = NULL, TimeInterface $time = NULL, AccountInterface $current_user) {
48     parent::__construct($entity_manager, $entity_type_bundle_info, $time);
49     $this->tempStoreFactory = $temp_store_factory;
50     $this->currentUser = $current_user;
51   }
52
53   /**
54    * {@inheritdoc}
55    */
56   public static function create(ContainerInterface $container) {
57     return new static(
58       $container->get('entity.manager'),
59       $container->get('user.private_tempstore'),
60       $container->get('entity_type.bundle.info'),
61       $container->get('datetime.time'),
62       $container->get('current_user')
63     );
64   }
65
66   /**
67    * {@inheritdoc}
68    */
69   public function form(array $form, FormStateInterface $form_state) {
70     // Try to restore from temp store, this must be done before calling
71     // parent::form().
72     $store = $this->tempStoreFactory->get('node_preview');
73
74     // Attempt to load from preview when the uuid is present unless we are
75     // rebuilding the form.
76     $request_uuid = \Drupal::request()->query->get('uuid');
77     if (!$form_state->isRebuilding() && $request_uuid && $preview = $store->get($request_uuid)) {
78       /** @var $preview \Drupal\Core\Form\FormStateInterface */
79
80       $form_state->setStorage($preview->getStorage());
81       $form_state->setUserInput($preview->getUserInput());
82
83       // Rebuild the form.
84       $form_state->setRebuild();
85
86       // The combination of having user input and rebuilding the form means
87       // that it will attempt to cache the form state which will fail if it is
88       // a GET request.
89       $form_state->setRequestMethod('POST');
90
91       $this->entity = $preview->getFormObject()->getEntity();
92       $this->entity->in_preview = NULL;
93
94       $form_state->set('has_been_previewed', TRUE);
95     }
96
97     /** @var \Drupal\node\NodeInterface $node */
98     $node = $this->entity;
99
100     if ($this->operation == 'edit') {
101       $form['#title'] = $this->t('<em>Edit @type</em> @title', [
102         '@type' => node_get_type_label($node),
103         '@title' => $node->label()
104       ]);
105     }
106
107     // Changed must be sent to the client, for later overwrite error checking.
108     $form['changed'] = [
109       '#type' => 'hidden',
110       '#default_value' => $node->getChangedTime(),
111     ];
112
113     $form = parent::form($form, $form_state);
114
115     $form['advanced']['#attributes']['class'][] = 'entity-meta';
116
117     $form['meta'] = [
118       '#type' => 'details',
119       '#group' => 'advanced',
120       '#weight' => -10,
121       '#title' => $this->t('Status'),
122       '#attributes' => ['class' => ['entity-meta__header']],
123       '#tree' => TRUE,
124       '#access' => $this->currentUser->hasPermission('administer nodes'),
125     ];
126     $form['meta']['published'] = [
127       '#type' => 'item',
128       '#markup' => $node->isPublished() ? $this->t('Published') : $this->t('Not published'),
129       '#access' => !$node->isNew(),
130       '#wrapper_attributes' => ['class' => ['entity-meta__title']],
131     ];
132     $form['meta']['changed'] = [
133       '#type' => 'item',
134       '#title' => $this->t('Last saved'),
135       '#markup' => !$node->isNew() ? format_date($node->getChangedTime(), 'short') : $this->t('Not saved yet'),
136       '#wrapper_attributes' => ['class' => ['entity-meta__last-saved']],
137     ];
138     $form['meta']['author'] = [
139       '#type' => 'item',
140       '#title' => $this->t('Author'),
141       '#markup' => $node->getOwner()->getUsername(),
142       '#wrapper_attributes' => ['class' => ['entity-meta__author']],
143     ];
144
145     $form['footer'] = [
146       '#type' => 'container',
147       '#weight' => 99,
148       '#attributes' => [
149         'class' => ['node-form-footer']
150       ]
151     ];
152     $form['status']['#group'] = 'footer';
153
154     // Node author information for administrators.
155     $form['author'] = [
156       '#type' => 'details',
157       '#title' => t('Authoring information'),
158       '#group' => 'advanced',
159       '#attributes' => [
160         'class' => ['node-form-author'],
161       ],
162       '#attached' => [
163         'library' => ['node/drupal.node'],
164       ],
165       '#weight' => 90,
166       '#optional' => TRUE,
167     ];
168
169     if (isset($form['uid'])) {
170       $form['uid']['#group'] = 'author';
171     }
172
173     if (isset($form['created'])) {
174       $form['created']['#group'] = 'author';
175     }
176
177     // Node options for administrators.
178     $form['options'] = [
179       '#type' => 'details',
180       '#title' => t('Promotion options'),
181       '#group' => 'advanced',
182       '#attributes' => [
183         'class' => ['node-form-options'],
184       ],
185       '#attached' => [
186         'library' => ['node/drupal.node'],
187       ],
188       '#weight' => 95,
189       '#optional' => TRUE,
190     ];
191
192     if (isset($form['promote'])) {
193       $form['promote']['#group'] = 'options';
194     }
195
196     if (isset($form['sticky'])) {
197       $form['sticky']['#group'] = 'options';
198     }
199
200     $form['#attached']['library'][] = 'node/form';
201
202     return $form;
203   }
204
205   /**
206    * Entity builder updating the node status with the submitted value.
207    *
208    * @param string $entity_type_id
209    *   The entity type identifier.
210    * @param \Drupal\node\NodeInterface $node
211    *   The node updated with the submitted values.
212    * @param array $form
213    *   The complete form array.
214    * @param \Drupal\Core\Form\FormStateInterface $form_state
215    *   The current state of the form.
216    *
217    * @see \Drupal\node\NodeForm::form()
218    *
219    * @deprecated in Drupal 8.4.x, will be removed before Drupal 9.0.0.
220    *   The "Publish" button was removed.
221    */
222   public function updateStatus($entity_type_id, NodeInterface $node, array $form, FormStateInterface $form_state) {
223     $element = $form_state->getTriggeringElement();
224     if (isset($element['#published_status'])) {
225       $node->setPublished($element['#published_status']);
226     }
227   }
228
229   /**
230    * {@inheritdoc}
231    */
232   protected function actions(array $form, FormStateInterface $form_state) {
233     $element = parent::actions($form, $form_state);
234     $node = $this->entity;
235     $preview_mode = $node->type->entity->getPreviewMode();
236
237     $element['submit']['#access'] = $preview_mode != DRUPAL_REQUIRED || $form_state->get('has_been_previewed');
238
239     $element['preview'] = [
240       '#type' => 'submit',
241       '#access' => $preview_mode != DRUPAL_DISABLED && ($node->access('create') || $node->access('update')),
242       '#value' => t('Preview'),
243       '#weight' => 20,
244       '#submit' => ['::submitForm', '::preview'],
245     ];
246
247     $element['delete']['#access'] = $node->access('delete');
248     $element['delete']['#weight'] = 100;
249
250     return $element;
251   }
252
253   /**
254    * Form submission handler for the 'preview' action.
255    *
256    * @param $form
257    *   An associative array containing the structure of the form.
258    * @param $form_state
259    *   The current state of the form.
260    */
261   public function preview(array $form, FormStateInterface $form_state) {
262     $store = $this->tempStoreFactory->get('node_preview');
263     $this->entity->in_preview = TRUE;
264     $store->set($this->entity->uuid(), $form_state);
265
266     $route_parameters = [
267       'node_preview' => $this->entity->uuid(),
268       'view_mode_id' => 'full',
269     ];
270
271     $options = [];
272     $query = $this->getRequest()->query;
273     if ($query->has('destination')) {
274       $options['query']['destination'] = $query->get('destination');
275       $query->remove('destination');
276     }
277     $form_state->setRedirect('entity.node.preview', $route_parameters, $options);
278   }
279
280   /**
281    * {@inheritdoc}
282    */
283   public function save(array $form, FormStateInterface $form_state) {
284     $node = $this->entity;
285     $insert = $node->isNew();
286     $node->save();
287     $node_link = $node->link($this->t('View'));
288     $context = ['@type' => $node->getType(), '%title' => $node->label(), 'link' => $node_link];
289     $t_args = ['@type' => node_get_type_label($node), '%title' => $node->link($node->label())];
290
291     if ($insert) {
292       $this->logger('content')->notice('@type: added %title.', $context);
293       drupal_set_message(t('@type %title has been created.', $t_args));
294     }
295     else {
296       $this->logger('content')->notice('@type: updated %title.', $context);
297       drupal_set_message(t('@type %title has been updated.', $t_args));
298     }
299
300     if ($node->id()) {
301       $form_state->setValue('nid', $node->id());
302       $form_state->set('nid', $node->id());
303       if ($node->access('view')) {
304         $form_state->setRedirect(
305           'entity.node.canonical',
306           ['node' => $node->id()]
307         );
308       }
309       else {
310         $form_state->setRedirect('<front>');
311       }
312
313       // Remove the preview entry from the temp store, if any.
314       $store = $this->tempStoreFactory->get('node_preview');
315       $store->delete($node->uuid());
316     }
317     else {
318       // In the unlikely case something went wrong on save, the node will be
319       // rebuilt and node form redisplayed the same way as in preview.
320       drupal_set_message(t('The post could not be saved.'), 'error');
321       $form_state->setRebuild();
322     }
323   }
324
325 }