This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /** |
||
3 | * @package advancedworkflow |
||
4 | * @todo UI/UX needs looking at for when current user has no pending and/or submitted items, (Current implementation is bog-standard <p> text) |
||
5 | */ |
||
6 | class AdvancedWorkflowAdmin extends ModelAdmin { |
||
7 | |||
8 | private static $menu_title = 'Workflows'; |
||
9 | private static $menu_priority = -1; |
||
10 | private static $url_segment = 'workflows'; |
||
11 | private static $menu_icon = "advancedworkflow/images/workflow-menu-icon.png"; |
||
12 | |||
13 | /** |
||
14 | * |
||
15 | * @var array Allowable actions on this controller. |
||
16 | */ |
||
17 | private static $allowed_actions = array( |
||
18 | 'export', |
||
19 | 'ImportForm' |
||
20 | ); |
||
21 | |||
22 | private static $url_handlers = array( |
||
23 | '$ModelClass/export/$ID!' => 'export', |
||
24 | '$ModelClass/$Action' => 'handleAction', |
||
25 | '' => 'index' |
||
26 | ); |
||
27 | |||
28 | private static $managed_models = 'WorkflowDefinition'; |
||
29 | |||
30 | private static $model_importers = array( |
||
31 | 'WorkflowDefinition' => 'WorkflowBulkLoader' |
||
32 | ); |
||
33 | |||
34 | private static $dependencies = array( |
||
35 | 'workflowService' => '%$WorkflowService', |
||
36 | ); |
||
37 | |||
38 | private static $fileEditActions = 'getCMSActions'; |
||
39 | |||
40 | /** |
||
41 | * Defaults are set in {@link getEditForm()}. |
||
42 | * |
||
43 | * @var array |
||
44 | */ |
||
45 | private static $fieldOverrides = array(); |
||
46 | |||
47 | /** |
||
48 | * @var WorkflowService |
||
49 | */ |
||
50 | public $workflowService; |
||
51 | |||
52 | /** |
||
53 | * Initialise javascript translation files |
||
54 | * |
||
55 | * @return void |
||
56 | */ |
||
57 | public function init() { |
||
58 | parent::init(); |
||
59 | Requirements::add_i18n_javascript('advancedworkflow/javascript/lang'); |
||
60 | Requirements::javascript('advancedworkflow/javascript/WorkflowField.js'); |
||
61 | Requirements::javascript('advancedworkflow/javascript/WorkflowGridField.js'); |
||
62 | Requirements::css('advancedworkflow/css/WorkflowField.css'); |
||
63 | Requirements::css('advancedworkflow/css/WorkflowGridField.css'); |
||
64 | } |
||
65 | |||
66 | /* |
||
67 | * Shows up to x2 GridFields for Pending and Submitted items, dependent upon the current CMS user and that user's permissions |
||
68 | * on the objects showing in each field. |
||
69 | */ |
||
70 | public function getEditForm($id = null, $fields = null) { |
||
71 | $form = parent::getEditForm($id, $fields); |
||
72 | |||
73 | // Show items submitted into a workflow for current user to action |
||
74 | $fieldName = 'PendingObjects'; |
||
75 | $pending = $this->userObjects(Member::currentUser(), $fieldName); |
||
76 | |||
77 | if(self::$fieldOverrides) { |
||
0 ignored issues
–
show
|
|||
78 | $displayFields = self::$fieldOverrides; |
||
79 | } else { |
||
80 | $displayFields = array( |
||
81 | 'Title' => _t('AdvancedWorkflowAdmin.Title', 'Title'), |
||
82 | 'LastEdited' => _t('AdvancedWorkflowAdmin.LastEdited', 'Changed'), |
||
83 | 'WorkflowTitle' => _t('AdvancedWorkflowAdmin.WorkflowTitle', 'Effective workflow'), |
||
84 | 'WorkflowStatus' => _t('AdvancedWorkflowAdmin.WorkflowStatus', 'Current action'), |
||
85 | ); |
||
86 | } |
||
87 | |||
88 | // Pending/Submitted items GridField Config |
||
89 | $config = new GridFieldConfig_Base(); |
||
90 | $config->addComponent(new GridFieldEditButton()); |
||
91 | $config->addComponent(new GridFieldDetailForm()); |
||
92 | $config->getComponentByType('GridFieldPaginator')->setItemsPerPage(5); |
||
93 | $columns = $config->getComponentByType('GridFieldDataColumns'); |
||
94 | $columns->setFieldFormatting($this->setFieldFormatting($config)); |
||
95 | |||
96 | if($pending->count()) { |
||
97 | $formFieldTop = GridField::create( |
||
98 | $fieldName, |
||
99 | $this->isAdminUser(Member::currentUser())? |
||
100 | _t( |
||
101 | 'AdvancedWorkflowAdmin.GridFieldTitleAssignedAll', |
||
102 | 'All pending items' |
||
103 | ): |
||
104 | _t( |
||
105 | 'AdvancedWorkflowAdmin.GridFieldTitleAssignedYour', |
||
106 | 'Your pending items'), |
||
107 | $pending, |
||
108 | $config |
||
109 | ); |
||
110 | |||
111 | $dataColumns = $formFieldTop->getConfig()->getComponentByType('GridFieldDataColumns'); |
||
112 | $dataColumns->setDisplayFields($displayFields); |
||
113 | |||
114 | $formFieldTop->setForm($form); |
||
115 | $form->Fields()->insertBefore($formFieldTop, 'WorkflowDefinition'); |
||
116 | } |
||
117 | |||
118 | // Show items submitted into a workflow by current user |
||
119 | $fieldName = 'SubmittedObjects'; |
||
120 | $submitted = $this->userObjects(Member::currentUser(), $fieldName); |
||
121 | if($submitted->count()) { |
||
122 | $formFieldBottom = GridField::create( |
||
123 | $fieldName, |
||
124 | $this->isAdminUser(Member::currentUser())? |
||
125 | _t( |
||
126 | 'AdvancedWorkflowAdmin.GridFieldTitleSubmittedAll', |
||
127 | 'All submitted items' |
||
128 | ): |
||
129 | _t( |
||
130 | 'AdvancedWorkflowAdmin.GridFieldTitleSubmittedYour', |
||
131 | 'Your submitted items'), |
||
132 | $submitted, |
||
133 | $config |
||
134 | ); |
||
135 | |||
136 | $dataColumns = $formFieldBottom->getConfig()->getComponentByType('GridFieldDataColumns'); |
||
137 | $dataColumns->setDisplayFields($displayFields); |
||
138 | |||
139 | $formFieldBottom->setForm($form); |
||
140 | $formFieldBottom->getConfig()->removeComponentsByType('GridFieldEditButton'); |
||
141 | $formFieldBottom->getConfig()->addComponent(new GridFieldWorkflowRestrictedEditButton()); |
||
142 | $form->Fields()->insertBefore($formFieldBottom, 'WorkflowDefinition'); |
||
143 | } |
||
144 | |||
145 | $grid = $form->Fields()->dataFieldByName('WorkflowDefinition'); |
||
146 | if ($grid) { |
||
147 | $grid->getConfig()->getComponentByType('GridFieldDetailForm')->setItemEditFormCallback(function ($form) { |
||
148 | $record = $form->getRecord(); |
||
149 | if ($record) { |
||
150 | $record->updateAdminActions($form->Actions()); |
||
151 | } |
||
152 | }); |
||
153 | |||
154 | $grid->getConfig()->getComponentByType('GridFieldDetailForm')->setItemRequestClass('WorkflowDefinitionItemRequestClass'); |
||
155 | $grid->getConfig()->addComponent(new GridFieldExportAction()); |
||
156 | $grid->getConfig()->removeComponentsByType('GridFieldExportButton'); |
||
157 | } |
||
158 | |||
159 | return $form; |
||
160 | } |
||
161 | |||
162 | /* |
||
163 | * @param Member $user |
||
164 | * @return boolean |
||
165 | */ |
||
166 | public function isAdminUser(Member $user) { |
||
167 | if(Permission::checkMember($user, 'ADMIN')) { |
||
168 | return true; |
||
169 | } |
||
170 | return false; |
||
171 | } |
||
172 | |||
173 | /* |
||
174 | * By default, we implement GridField_ColumnProvider to allow users to click through to the PagesAdmin. |
||
175 | * We would also like a "Quick View", that allows users to quickly make a decision on a given workflow-bound content-object |
||
176 | */ |
||
177 | public function columns() { |
||
178 | $fields = array( |
||
179 | 'Title' => array( |
||
180 | 'link' => function($value, $item) { |
||
181 | $pageAdminLink = singleton('CMSPageEditController')->Link('show'); |
||
182 | return sprintf('<a href="%s/%s">%s</a>',$pageAdminLink,$item->Link,$value); |
||
183 | } |
||
184 | ), |
||
185 | 'WorkflowStatus' => array( |
||
186 | 'text' => function($value, $item) { |
||
187 | return $item->WorkflowCurrentAction; |
||
188 | } |
||
189 | ) |
||
190 | ); |
||
191 | return $fields; |
||
192 | } |
||
193 | |||
194 | /* |
||
195 | * Discreet method used by both intro gridfields to format the target object's links and clickable text |
||
196 | * |
||
197 | * @param GridFieldConfig $config |
||
198 | * @return array $fieldFormatting |
||
199 | */ |
||
200 | public function setFieldFormatting(&$config) { |
||
201 | $fieldFormatting = array(); |
||
202 | // Parse the column information |
||
203 | foreach($this->columns() as $source => $info) { |
||
204 | if(isset($info['link']) && $info['link']) { |
||
205 | $fieldFormatting[$source] = '<a href=\"$ObjectRecordLink\">$value</a>'; |
||
206 | } |
||
207 | if(isset($info['text']) && $info['text']) { |
||
208 | $fieldFormatting[$source] = $info['text']; |
||
209 | } |
||
210 | } |
||
211 | return $fieldFormatting; |
||
212 | } |
||
213 | |||
214 | /** |
||
215 | * Get WorkflowInstance Target objects to show for users in initial gridfield(s) |
||
216 | * |
||
217 | * @param Member $member |
||
218 | * @param string $fieldName The name of the gridfield that determines which dataset to return |
||
219 | * @return DataList |
||
220 | * @todo Add the ability to see embargo/expiry dates in report-gridfields at-a-glance if QueuedJobs module installed |
||
221 | */ |
||
222 | public function userObjects(Member $user, $fieldName) { |
||
223 | $list = new ArrayList(); |
||
224 | $userWorkflowInstances = $this->getFieldDependentData($user, $fieldName); |
||
225 | foreach($userWorkflowInstances as $instance) { |
||
226 | if(!$instance->TargetID || !$instance->DefinitionID) { |
||
227 | continue; |
||
228 | } |
||
229 | // @todo can we use $this->getDefinitionFor() to fetch the "Parent" definition of $instance? Maybe define $this->workflowParent() |
||
230 | $effectiveWorkflow = DataObject::get_by_id('WorkflowDefinition', $instance->DefinitionID); |
||
231 | $target = $instance->getTarget(); |
||
232 | if(!is_object($effectiveWorkflow) || !$target) { |
||
233 | continue; |
||
234 | } |
||
235 | $instance->setField('WorkflowTitle',$effectiveWorkflow->getField('Title')); |
||
236 | $instance->setField('WorkflowCurrentAction',$instance->getCurrentAction()); |
||
237 | // Note the order of property-setting here, somehow $instance->Title is overwritten by the Target Title property.. |
||
238 | $instance->setField('Title',$target->getField('Title')); |
||
239 | $instance->setField('LastEdited',$target->getField('LastEdited')); |
||
240 | if (method_exists($target, 'CMSEditLink')) { |
||
241 | $instance->setField('ObjectRecordLink', Controller::join_links(Director::absoluteBaseURL(), $target->CMSEditLink())); |
||
242 | } |
||
243 | |||
244 | $list->push($instance); |
||
245 | } |
||
246 | return $list; |
||
247 | } |
||
248 | |||
249 | /* |
||
250 | * Return content-object data depending on which gridfeld is calling for it |
||
251 | * |
||
252 | * @param Member $user |
||
253 | * @param string $fieldName |
||
254 | */ |
||
255 | public function getFieldDependentData(Member $user, $fieldName) { |
||
256 | if($fieldName == 'PendingObjects') { |
||
257 | return $this->workflowService->userPendingItems($user); |
||
258 | } |
||
259 | if($fieldName == 'SubmittedObjects') { |
||
260 | return $this->workflowService->userSubmittedItems($user); |
||
261 | } |
||
262 | } |
||
263 | |||
264 | /** |
||
265 | * Spits out an exported version of the selected WorkflowDefinition for download. |
||
266 | * |
||
267 | * @param \SS_HTTPRequest $request |
||
268 | * @return \SS_HTTPResponse |
||
269 | */ |
||
270 | public function export(SS_HTTPRequest $request) { |
||
271 | $url = explode('/', $request->getURL()); |
||
272 | $definitionID = end($url); |
||
273 | if($definitionID && is_numeric($definitionID)) { |
||
274 | $exporter = new WorkflowDefinitionExporter($definitionID); |
||
275 | $exportFilename = WorkflowDefinitionExporter::$export_filename_prefix.'-'.$definitionID.'.yml'; |
||
276 | $exportBody = $exporter->export(); |
||
277 | $fileData = array( |
||
278 | 'name' => $exportFilename, |
||
279 | 'mime' => 'text/x-yaml', |
||
280 | 'body' => $exportBody, |
||
281 | 'size' => $exporter->getExportSize($exportBody) |
||
282 | ); |
||
283 | return $exporter->sendFile($fileData); |
||
284 | } |
||
285 | } |
||
286 | |||
287 | /** |
||
288 | * Required so we can simply change the visible label of the "Import" button and lose some redundant form-fields. |
||
289 | * |
||
290 | * @return Form |
||
291 | */ |
||
292 | public function ImportForm() { |
||
293 | $form = parent::ImportForm(); |
||
294 | if(!$form) { |
||
295 | return; |
||
296 | } |
||
297 | |||
298 | $form->unsetAllActions(); |
||
299 | $newActionList = new FieldList(array( |
||
300 | new FormAction('import', _t('AdvancedWorkflowAdmin.IMPORT', 'Import workflow')) |
||
301 | )); |
||
302 | $form->Fields()->fieldByName('_CsvFile')->getValidator()->setAllowedExtensions(array('yml', 'yaml')); |
||
303 | $form->Fields()->removeByName('EmptyBeforeImport'); |
||
304 | $form->setActions($newActionList); |
||
305 | |||
306 | return $form; |
||
307 | } |
||
308 | } |
||
309 | |||
310 | class WorkflowDefinitionItemRequestClass extends GridFieldDetailForm_ItemRequest { |
||
311 | public function updatetemplateversion($data, Form $form, $request) { |
||
312 | $record = $form->getRecord(); |
||
313 | if ($record) { |
||
314 | $record->updateFromTemplate(); |
||
315 | } |
||
316 | return $form->loadDataFrom($form->getRecord())->forAjaxTemplate(); |
||
317 | } |
||
318 | } |
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.