Problem/Motivation
6 node action plugins have nearly identical implementations of both execute and access methods. Those plugins are:
- PublishNode
- UnpublishNode
- StickyNode
- UnstickyNode
- PromoteNode
- DemoteNode
all in Drupal\node\Plugin\Action
namespace. The only difference is the name of the field (ie. status, sticky or promoted) and the value to set (NODE_PUBLISHED, ...). There are two problems with this approach:
- Each action plugin is reimplementing the same logic.
- If you end up needing to write a similar action for your own entity, you need to copy that same structure making the amount of code to maintain even bigger.
Proposed resolution
Long story short - all the actions mentioned above do the same thing. They update a field on an entity, so let's turn this (times 6)
class PublishNode extends <strong>ActionBase</strong> {
/**
* {@inheritdoc}
*/
public function execute($entity = NULL) {
$entity->status = NODE_PUBLISHED;
$entity->save();
}
/**
* {@inheritdoc}
*/
public function access($object, AccountInterface $account = NULL, $return_as_object = FALSE) {
/** @var \Drupal\node\NodeInterface $object */
$result = $object->access('update', $account, TRUE)
->andIf($object->status->access('edit', $account, TRUE));
return $return_as_object ? $result : $result->isAllowed();
}
}
into this
class PublishNode extends <strong>FieldUpdateActionBase</strong> {
/**
* {@inheritdoc}
*/
protected function getFieldsToUpdate() {
return ['status' => NODE_PUBLISHED];
}
}
and move all common code to base class.
Results:
- Less code to maintain.
- Bonus: better DX. Implementing a new action (eg.
PublishMyCustomEntity
) becomes super easy. No need to worry about field or entity access, as base class covers that. - Bonus: Defining complex actions, such that update more than one field is a breeze:
class FinishTask extends <strong>FieldUpdateActionBase</strong> {
/**
* {@inheritdoc}
*/
protected function getFieldsToUpdate() {
return [
'status' => TASK_FINISHED,
'progress' => '100%',
'assignee' => null,
];
}
}
Comments welcome.
Remaining tasks
Decide where to put the base class. Drupal\Core\Field
? Drupal\Core\Action
?
User interface changes
None
API changes
None
Data model changes
None
Comment | File | Size | Author |
---|---|---|---|
#16 | interdiff.txt | 1.34 KB | blazey |
#15 | action_base_class-2805993-15.patch | 9.11 KB | blazey |
#12 | action_base_class-2805993-12.patch | 9.26 KB | trzcinski.t@gmail.com |
#10 | interdiff.txt | 1.4 KB | blazey |
#10 | action_base_class-2805993-10.patch | 9.1 KB | blazey |
Comments
Comment #2
blazey CreditAttribution: blazey as a volunteer commentedComment #3
blazey CreditAttribution: blazey as a volunteer commentedComment #4
blazey CreditAttribution: blazey as a volunteer commentedComment #5
blazey CreditAttribution: blazey as a volunteer commentedTo test:
Comment #6
Lund CreditAttribution: Lund at Adapt commentedI tested the patch provided following the steps given, and it works as intended. Also tested that other users without the right permissions cant change the state of the node.
Comment #7
Virbius CreditAttribution: Virbius as a volunteer and commentedDone further testing of dropdown options, including selecting Sticky when already Sticky, and the settings were reflected when in Edit mode. Did this for Publish/Unpublish, Sticky/Unsticky, and finally Delete. Did this with a second node present but unselected, and all OK.
Also did the same with 2 node in parallel, while not selecting a 3rd.
This was done at DrupalCon Dublin 2016
Comment #8
alexpottNeeds a class doc to describe what it is for and how to implement.
This looks a bit out of place
Comment #9
alexpottShould start with something like "Gets..."
Needs a description - should be similar to the one line.
Comment #10
blazey CreditAttribution: blazey as a volunteer commentedThank you Alex. Attached patch is addressing all the points from #8 and #9. First draft of change record: https://www.drupal.org/node/2817655. Does it sound acceptable in English?
Comment #12
trzcinski.t@gmail.com CreditAttribution: trzcinski.t@gmail.com as a volunteer commentedThe patch was not applying to 8.3.3 and 8.4.x. Attaching a reroll with replaced the use of deprecated constants.
Comment #13
trzcinski.t@gmail.com CreditAttribution: trzcinski.t@gmail.com as a volunteer commentedSince the tests passed I am marking this as RTBC (I have tested the thing before, now just re-rolled :) ).
Comment #14
Wim LeersMust be a single line.
This is missing the right formatting
This is the wrong notation.
Comment #15
blazey CreditAttribution: blazey as a volunteer commentedThanks for review. How about now?
Comment #16
blazey CreditAttribution: blazey as a volunteer commentedAttaching an interdiff.
Comment #17
Wim LeersThanks!
Comment #18
larowlannit: two empty lines here instead of one, can be fixed on commit
Comment #20
catchCommitted 18cffdc and pushed to 8.4.x. Thanks!