WorkflowTransitionListBuilder.php
9.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
<?php
/**
* @file
* Contains \Drupal\workflow\WorkflowTransitionListBuilder.
*/
namespace Drupal\workflow;
use Drupal\Component\Utility\Html;
use Drupal\Core\Entity\EntityListBuilder;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Form\FormInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\workflow\Entity\WorkflowTransition;
use Drupal\workflow\Entity\WorkflowTransitionInterface;
define('WORKFLOW_MARK_STATE_IS_DELETED', '*');
/**
* Defines a class to build a draggable listing of Workflow State entities.
*
* @see \Drupal\workflow\Entity\WorkflowState
*/
class WorkflowTransitionListBuilder extends EntityListBuilder implements FormInterface {
/**
* A variable to pass the entity of a transition to the ListBuilder.
* @todo: There should be a better way.
*
* @var EntityInterface
*/
public $workflow_entity;
/**
* {@inheritdoc}
*/
protected $limit = 50;
/**
* Indicates if a footer must be generated.
*
* @var bool
*/
protected $footer_needed = FALSE;
/**
* {@inheritdoc}
*/
public function load() {
$entities = array();
// TODO: D8-port: get entity from proper core methods.
/* @var $entity EntityInterface */
$entity = $this->workflow_entity; // This is a custom variable.
// Get the field name. It is yet unknown. N.B. This does not work with multiple workflows per entity!
$field_name = workflow_get_field_name($entity);
if ($field_name) {
$entity_type = $entity->getEntityTypeId();
$entity_id = $entity->id();
// @todo D8-port: document $limit.
// @todo d8-port: $limit should be used in pager, not in load().
$this->limit = \Drupal::config('workflow.settings')
->get('workflow_states_per_page');
$limit = $this->limit;
// Get Transitions with higest timestamp first.
$entities = WorkflowTransition::loadMultipleByProperties($entity_type, array($entity_id), [], $field_name, '', $limit, 'DESC');
}
return $entities;
}
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'workflow_transiton_history_form';
}
/**
* {@inheritdoc}
*
* Building the header and content lines for the contact list.
*
* Calling the parent::buildHeader() adds a column for the possible actions
* and inserts the 'edit' and 'delete' links as defined for the entity type.
*/
public function buildHeader() {
$header['timestamp'] = $this->t('Date');
$header['from_state'] = $this->t('From State');
$header['to_state'] = $this->t('To State');
$header['user_name'] = $this->t('By');
$header['comment'] = $this->t('Comment');
// column 'Operations' is now added by core.
//$header['operations'] = $this->t('Operations');
return $header + parent::buildHeader();
}
/**
* {@inheritdoc}
*
* @todo D8-port: add D7-theming to TransitionListBuilder.
*/
public function buildRow(EntityInterface $transition) {
// Show the history table.
$current_themed = FALSE;
/* @var $transition WorkflowTransitionInterface */
$entity = $transition->getTargetEntity();
$field_name = $transition->getFieldName();
$current_sid = workflow_node_current_state($entity, $field_name);
$to_state = $transition->getToState();
if (!$to_state) {
// This is an invalid/deleted state.
$to_label = WORKFLOW_MARK_STATE_IS_DELETED;
// Add a footer to explain the addition.
$this->footer_needed = TRUE;
}
else {
$label = Html::escape($this->t($to_state->label()));
if ($transition->getToSid() == $current_sid && $to_state->isActive() && !$current_themed) {
$to_label = $label;
if (!$current_themed) {
// Make a note that we have themed the current state; other times in the history
// of this entity where the entity was in this state do not need to be specially themed.
$current_themed = TRUE;
}
}
elseif (!$to_state->isActive()) {
$to_label = $label . WORKFLOW_MARK_STATE_IS_DELETED;
// Add a footer to explain the addition.
$this->footer_needed = TRUE;
}
else {
// Regular state.
$to_label = $label;
}
}
unset($to_state); // Not needed anymore.
$from_state = $transition->getFromState();
if (!$from_state) {
// This is an invalid/deleted state.
$from_label = WORKFLOW_MARK_STATE_IS_DELETED;
// Add a footer to explain the addition.
$this->footer_needed = TRUE;
}
else {
$label = Html::escape($this->t($from_state->label()));
if (!$from_state->isActive()) {
$from_label = $label . WORKFLOW_MARK_STATE_IS_DELETED;
// Add a footer to explain the addition.
$this->footer_needed = TRUE;
}
else {
// Regular state.
$from_label = $label;
}
}
unset($from_state); // Not needed anymore.
$owner = $transition->getOwner();
$variables = array(
'transition' => $transition,
'extra' => '',
'from_label' => $from_label,
'to_label' => $to_label,
'user' => $owner,
);
// Allow other modules to modify the row.
\Drupal::moduleHandler()->alter('workflow_history', $variables);
// 'class' => array('workflow_history_row'), // TODO D8-port
$row['timestamp']['data'] = $transition->getTimestampFormatted(); // 'class' => array('timestamp')
// html_entity_decode() transforms chars like '&' correctly.
$row['from_state']['data'] = html_entity_decode($from_label); // 'class' => array('previous-state-name'))
$row['to_state']['data'] = html_entity_decode($to_label); // 'class' => array('state-name'))
$row['user_name']['data'] = $owner->getUsername(); // 'class' => array('user-name')
$row['comment']['data'] = html_entity_decode($transition->getComment()); // 'class' => array('log-comment')
// $row['comment'] = array(
// '#type' => 'textarea',
// '#default_value' => $transition->getComment(),
// );
// Column 'Operations' is now added by core.
// D7: $row['operations']['data'] = $this->buildOperations($entity);
$row += parent::buildRow($transition);
return $row;
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
workflow_debug(__FILE__, __FUNCTION__, __LINE__); // @todo D8-port: still test this snippet.
$form = parent::buildForm($form, $form_state);
return $form;
}
/**
* {@inheritdoc}
*
* Builds the entity listing as renderable array for table.html.twig.
*
* @todo Add a link to add a new item to the #empty text.
*/
public function render() {
$build = array();
// @todo d8-port: get pager working.
$this->limit = \Drupal::config('workflow.settings')->get('workflow_states_per_page'); // TODO D8-port
// $output .= theme('pager', array('tags' => $limit)); // TODO D8-port
// @todo d8-port: get core title working: $build['table']['#title'] by getTitle() is not working.
$build['workflow_list_title'] = array(
'#markup' => $this->getTitle(),
);
$build += parent::render();
// Add a footer. This is not yet added in EntityListBilder::render()
if ($this->footer_needed) { // TODO D8-port: test this.
// Two variants. First variant is official, but I like 2nd better.
/*
$build['table']['#footer'] = array(
array(
'class' => array('footer-class'),
'data' => array(
array(
'data' => WORKFLOW_MARK_STATE_IS_DELETED . ' ' . t('State is no longer available.'),
'colspan' => count($build['table']['#header']),
),
),
),
);
*/
$build['workflow_footer'] = array(
'#markup' => WORKFLOW_MARK_STATE_IS_DELETED . ' ' . t('State is no longer available.'),
'#weight' => 500, // @todo Make this better.
);
}
return $build;
}
/**
* Just for reference: parent::getOperations calls 2 hooks/alters.
* {@inheritdoc}
*/
// public function getOperations(EntityInterface $entity) {
// $operations = $this->getDefaultOperations($entity);
// $operations += $this->moduleHandler()->invokeAll('entity_operation', array($entity));
// $this->moduleHandler->alter('entity_operation', $operations, $entity);
// uasort($operations, '\Drupal\Component\Utility\SortArray::sortByWeightElement');
//
// return $operations;
// }
/**
* {@inheritdoc}
*/
public function getDefaultOperations(EntityInterface $entity) {
$operations = parent::getDefaultOperations($entity);
/* @var $transition WorkflowTransitionInterface */
$transition = $entity;
if (isset($operations['edit'])) {
$destination = \Drupal::destination()->getAsArray();
$operations['edit']['query'] = $destination;
}
return $operations;
}
/**
* Gets the title of the page.
*
* @return string
* A string title of the page.
*/
protected function getTitle() {
return $this->t('Workflow history');
}
/**
* {@inheritdoc}
*/
public function validateForm(array &$form, FormStateInterface $form_state) {
return;
}
/**
* {@inheritdoc}
*
* Overrides DraggableListBuilder::submitForm().
* The WorkflowState entities are always saved.
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
}
}