forked from kaliop-uk/ezworkflowenginebundle
/
ezworkflowenginehooktype.php
295 lines (261 loc) · 12.9 KB
/
ezworkflowenginehooktype.php
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
<?php
class eZWorkflowEngineHookType extends eZWorkflowEventType
{
const WORKFLOW_TYPE_STRING = 'ezworkflowenginehook';
static $signalMapping = array(
'content_addlocation' => array( 'pre' => false, 'post' => 'LocationService\CreateLocationSignal' ),
// this legacy operation does not allow us to retrieve in all scenarios the object_id, needed for the corresponding signal
//'content_delete' => array( 'pre' => false, 'post' => 'ContentService\DeleteContentSignal' ),
'content_hide' => array( 'pre' => false, 'post' => 'LocationService\HideLocationSignal' ),
'content_move' => array( 'pre' => false, 'post' => 'LocationService\MoveSubtreeSignal' ),
'content_publish' => array( 'pre' => false, 'post' => 'ContentService\PublishVersionSignal' ),
// this legacy operation does not allow us to retrieve in all scenarios the object_id, needed for the corresponding signal
//'content_removelocation' => array( 'pre' => false, 'post' => 'LocationService\DeleteLocationSignal' ),
// this legacy operation does not seem to have any corresponding eZ5 signal...
//'content_removetranslation' => '',
'content_sort' => array( 'pre' => false, 'post' => 'LocationService\UpdateLocationSignal' ),
'content_swap' => array( 'pre' => false, 'post' => 'LocationService\SwapLocationSignal' ),
'content_updatealwaysavailable' => array( 'pre' => false, 'post' => 'ContentService\UpdateContentMetadataSignal' ),
'content_updateinitiallanguage' => array( 'pre' => false, 'post' => 'ContentService\UpdateContentMetadataSignal' ),
'content_updatemainassignment' => array( 'pre' => false, 'post' => 'ContentService\UpdateContentMetadataSignal' ),
// this legacy operation needs hackish workarounds to retrieve the modified state(s), needed for the corresponding signal
//'content_updateobjectstate' => 'ObjectStateService\SetContentStateSignal' ),
'content_updatepriority' => array( 'pre' => false, 'post' => 'LocationService\UpdateLocationSignal' ),
'content_updatesection' => array( 'pre' => false, 'post' => 'SectionService\AssignSectionSignal' ),
);
/**
* @todo we should hook to 'after anything' only instead of just 'anything' for known signals, as they are all of type 'after'
*/
public function __construct()
{
$this->eZWorkflowEventType( self::WORKFLOW_TYPE_STRING, ezpI18n::tr( 'ezworkflowengine/eventtypes', 'Run WorkFlowEngineBundle workflows' ) );
$this->setTriggerTypes( array( '*' => true ) );
}
public function execute( $process, $event )
{
$parameters = $process->attribute( 'parameter_list' );
$tmp = explode( '_', $parameters['trigger_name'], 2 );
$triggerName = reset( $tmp );
$operationName = $parameters['module_name'] . '_' . $parameters['module_function'];
$signalName = $this->getsignalName( $triggerName, $operationName );
if ( !$signalName )
{
eZDebug::writeError( "Trigger '$triggerName $operationName' can not be mapped to eZ5 workflow signal. Aborting eZ4 workflow" );
return eZWorkflowType::STATUS_REJECTED;
}
$signalsParameters = $this->convertParameters( $triggerName, $operationName, $parameters );
if ( !$signalsParameters )
{
eZDebug::writeNotice( "Parameters for trigger '$triggerName $operationName' do not map to an eZ5 workflow. Continuing the eZ4 workflow" );
// this is a way to gracefully avoid triggering eZ5 workflows without failing the ez4 one
return eZWorkflowType::STATUS_ACCEPTED;
}
foreach ($signalsParameters as $signalParameters)
{
if ( !is_array( $signalParameters ) || ! count( $signalParameters ) )
{
eZDebug::writeError( "Parameters for trigger '$triggerName $operationName' can not be mapped to eZ5 workflow parameters. Aborting eZ4 workflow" );
return eZWorkflowType::STATUS_REJECTED;
}
$signalParameters['legacyTrigger'] = $triggerName;
$signalParameters['legacyOperation'] = $operationName;
$serviceContainer = ezpKernel::instance()->getServiceContainer();
$workflowService = $serviceContainer->get( 'ez_workflowengine_bundle.workflow_service' );
try
{
eZDebug::writeDebug( "Triggering any eZ5 workflows available for signal '$signalName' with parameters:" .
preg_replace( "/\n+/s", ' ', preg_replace('/^(Array| +|\(|\))/m', '', print_r( $signalParameters, true ) ) ),
__METHOD__
);
$workflowService->triggerWorkflow( $signalName, $signalParameters );
} catch ( \Exception $e )
{
eZDebug::writeError( $e->getMessage(), __METHOD__ );
return eZWorkflowType::STATUS_REJECTED;
}
}
return eZWorkflowType::STATUS_ACCEPTED;
}
/**
* Returns the eZ5 Signal known to map to the eZ4 Operation. If mapping is unknown, the eZ4 Operation name is returned
* @param string $triggerName
* @param string $operationName
* @return string mixed
*/
protected function getsignalName( $triggerName, $operationName )
{
if ( !isset( self::$signalMapping[$operationName][$triggerName] ) )
{
return $triggerName . '_' . $operationName;
}
return self::$signalMapping[$operationName][$triggerName];
}
/**
* @param $triggerName
* @param $operationName
* @param array $parameters
* @return array[] Each element is an array of parameters, used to trigger an ez5 workflow. Return array( false )
* for error conditions and array() to ignore ez5 workflows but continue the ez4 one
*/
protected function convertParameters( $triggerName, $operationName, array $parameters )
{
/// @see https://doc.ez.no/display/EZP/Signals+reference
switch( $operationName )
{
case 'content_addlocation':
$out = array();
// loop over all locations of content and find the ones which are children of the parents from the trigger
// NB: will break if eZ allows to create 2 locations in the same place for a single content...
$locations = eZContentObjectTreeNode::fetchByContentObjectID($parameters['object_id']);
foreach( $parameters['select_node_id_array'] as $parentNodeId )
{
foreach( $locations as $contentLocation )
{
if ( $contentLocation->attribute( 'parent_node_id' ) == $parentNodeId )
{
$out[] = array(
'contentId' => $parameters['object_id'],
/// @todo grab location id of created node
'locationId' => $contentLocation->attribute( 'node_id' ),
);
break;
}
}
}
return $out;
/*case 'content_delete':
/// @todo this only works on BEFORE trigger (or when using trash): we get a list of nodes and need to find the object...
return array(
'contentId' => $parameters['node_id']
);*/
case 'content_hide':
$objectId = $this->objectIdFromNodeId($parameters['node_id']);
if ( !$objectId )
{
return array( false );
}
return array( array(
'locationId' => $parameters['node_id'],
'contentId' => $objectId,
) );
case 'content_move':
return array( array(
'subtreeId' => $parameters['node_id'],
'newParentLocationId' => $parameters['new_parent_node_id'],
) );
case 'content_publish':
return array( array(
'contentId' => $parameters['object_id'],
'versionNo' => $parameters['version'],
) );
/*case 'content_removelocation':
$out = array();
foreach( $parameters['node_list'] as $nodeId )
{
if ( is_object( $nodeId ) )
{
$node = $nodeId;
$nodeId = $node->attribute( 'node_id' );
}
else
{
// note: this will most likely fail, as we get the node ids of nodes just removed...
$node = \eZContentObjectTreeNode::fetch( $nodeId );
if ( !$node )
{
return array( false );
}
}
$object = $node->attribute( 'content' );
if ( !$object )
{
return array( false );
}
$objectId = $object->attribute( 'id' );
$out[] = array(
'contentId' => $objectId,
'locationId' => $nodeId,
);
}
return $out;*/
//case 'content_removetranslation':
case 'content_sort':
$objectId = $this->objectIdFromNodeId( $parameters['node_id'] );
if ( !$objectId )
{
return array( false );
}
return array( array(
'contentId' => $objectId,
'locationId' => $parameters['node_id'],
) );
case 'content_swap':
$objectId1 = $this->objectIdFromNodeId( $parameters['node_id'] );
$objectId2 = $this->objectIdFromNodeId( $parameters['selected_node_id'] );
if ( !$objectId1 || !$objectId2 )
{
return array( false );
}
return array( array(
'content1Id' => $objectId1,
'location1Id' => $parameters['node_id'],
'content2Id' => $objectId2,
'location2Id' => $parameters['selected_node_id'],
) );
case 'content_updatemainassignment':
return array( array(
'contentId' => $parameters['object_id'],
) );
case 'content_updatepriority':
$objectId = $this->objectIdFromNodeId($parameters['node_id']);
if ( !$objectId )
{
return array( false );
}
return array( array(
'contentId' => '',
'locationId' => $parameters['node_id'],
) );
case 'content_updatesection':
$objectId = $this->objectIdFromNodeId($parameters['node_id']);
if ( !$objectId )
{
return array( false );
}
return array( array(
'contentId' => $objectId,
'sectionId' => $parameters['selected_section_id'],
) );
case 'content_updateinitiallanguage':
return array( array(
'contentId' => $parameters['object_id'],
) );
case 'content_updatealwaysavailable':
return array( array(
'contentId' => $parameters['object_id'],
) );
/*case 'content_updateobjectstate':
/// @todo we get an array of all states, but the eZ5 event needs to know which one changed
return array(
'contentId' => $parameters['object_id'],
'objectStateGroupId' => '',
'objectStateId' => '',
);*/
// in case of an unmapped legacy operation, we let through all parameters unmodified - except a few known ones
// (is it really a good idea to remove the known params?)
default:
return array( array_diff_key( $parameters, array( 'workflow_id', 'trigger_name', 'module_name', 'module_function', 'user_id' ) ) );
}
}
protected function objectIdFromNodeId( $nodeID )
{
$node = eZContentObjectTreeNode::fetch( $nodeID );
if ( !is_object( $node ) )
{
eZDebug::writeError( 'Unable to fetch node ' . $nodeID, __METHOD__ );
return null;
}
return $node->attribute( 'contentobject_id' );
}
}
eZWorkflowEventType::registerEventType( eZWorkflowEngineHookType::WORKFLOW_TYPE_STRING, 'eZWorkflowEngineHookType' );