Skip to content

Commit dc2238c

Browse files
committed
Allow for use with any event
By allowing the behavior to act on any event, it's possible to easily cater for soft delete (deleted_date) or any kind of custom event (approval_date, rejection_date, published_date)
1 parent 2e01e08 commit dc2238c

File tree

2 files changed

+64
-15
lines changed

2 files changed

+64
-15
lines changed

Cake/Model/Behavior/TimestampBehavior.php

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,22 @@ class TimestampBehavior extends Behavior {
2626
*
2727
* These are merged with user-provided settings when the behavior is used.
2828
*
29+
* events - an event-name keyed array of which fields to update, and when, for a given event
30+
* possible values for when a field will be updated are true, "new" or "existing" to set the
31+
* field value always, only when a new record or only when an existing record.
32+
*
2933
* refreshTimestamp - if true (the default) the timestamp used will be the current time when
3034
* the code is executed, to set to an explicit date time value - set refreshTimetamp to false
3135
* and call setTimestamp() on the behavior class before use.
3236
*
3337
* @var array
3438
*/
3539
protected $_defaultSettings = [
36-
'fields' => [
37-
'created' => 'created',
38-
'updated' => 'modified'
40+
'events' => [
41+
'Model.beforeSave' => [
42+
'created' => 'new',
43+
'modified' => true,
44+
]
3945
],
4046
'refreshTimestamp' => true
4147
];
@@ -60,26 +66,51 @@ public function __construct(Table $table, array $settings = []) {
6066
}
6167

6268
/**
63-
* beforeSave
69+
* handleEvent
6470
*
6571
* There is only one event handler, it can be configured to be called for any event
6672
*
6773
* @param Event $event
6874
* @param Entity $entity
6975
* @return true (irrespective of the behavior logic, the save will not be prevented)
7076
*/
71-
public function beforeSave(Event $event, Entity $entity) {
77+
public function handleEvent(Event $event, Entity $entity) {
78+
$eventName = $event->name();
7279
$settings = $this->settings();
80+
if (!isset($settings['events'][$eventName])) {
81+
return true;
82+
}
83+
7384
$new = $entity->isNew() !== false;
7485

75-
if ($new) {
76-
$this->_updateField($entity, $settings['fields']['created'], $settings['refreshTimestamp']);
86+
foreach($settings['events'][$eventName] as $field => $when) {
87+
if (
88+
$when === true ||
89+
($when === 'new' && $new) ||
90+
($when === 'existing' && !$new)
91+
) {
92+
$this->_updateField($entity, $field, $settings['refreshTimestamp']);
93+
}
7794
}
78-
$this->_updateField($entity, $settings['fields']['updated'], $settings['refreshTimestamp']);
7995

8096
return true;
8197
}
8298

99+
/**
100+
* implementedEvents
101+
*
102+
* The implemented events of this behavior depend on configuration
103+
*
104+
* @return array
105+
*/
106+
public function implementedEvents() {
107+
$events = array_flip(array_keys($this->_settings['events']));
108+
foreach($events as &$method) {
109+
$method = 'handleEvent';
110+
}
111+
return $events;
112+
}
113+
83114
/**
84115
* getTimestamp
85116
*

Cake/Test/TestCase/Model/Behavior/TimestampBehaviorTest.php

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,30 @@ class TimestampBehaviorTest extends TestCase {
2929
*
3030
* @return void
3131
*/
32-
public function testImplementedEvents() {
32+
public function testImplementedEventsDefault() {
3333
$table = $this->getMock('Cake\ORM\Table');
3434
$this->Behavior = new TimestampBehavior($table);
3535

3636
$expected = [
37-
'Model.beforeSave' => 'beforeSave'
37+
'Model.beforeSave' => 'handleEvent'
38+
];
39+
$this->assertEquals($expected, $this->Behavior->implementedEvents());
40+
}
41+
42+
/**
43+
* testImplementedEventsCustom
44+
*
45+
* The behavior allows for handling any event - test an example
46+
*
47+
* @return void
48+
*/
49+
public function testImplementedEventsCustom() {
50+
$table = $this->getMock('Cake\ORM\Table');
51+
$settings = ['events' => ['Something.special' => ['date_specialed' => true]]];
52+
$this->Behavior = new TimestampBehavior($table, $settings);
53+
54+
$expected = [
55+
'Something.special' => 'handleEvent'
3856
];
3957
$this->assertEquals($expected, $this->Behavior->implementedEvents());
4058
}
@@ -53,7 +71,7 @@ public function testCreatedAbsent() {
5371
$event = new Event('Model.beforeSave');
5472
$entity = new Entity(['name' => 'Foo']);
5573

56-
$return = $this->Behavior->beforeSave($event, $entity);
74+
$return = $this->Behavior->handleEvent($event, $entity);
5775
$this->assertTrue($return, 'Handle Event is expected to always return true');
5876
$this->assertSame($ts, $entity->created, 'Created timestamp is expected to be the mocked value');
5977
}
@@ -73,7 +91,7 @@ public function testCreatedPresent() {
7391
$existingValue = new \DateTime('2011-11-11');
7492
$entity = new Entity(['name' => 'Foo', 'created' => $existingValue]);
7593

76-
$return = $this->Behavior->beforeSave($event, $entity);
94+
$return = $this->Behavior->handleEvent($event, $entity);
7795
$this->assertTrue($return, 'Handle Event is expected to always return true');
7896
$this->assertSame($existingValue, $entity->created, 'Created timestamp is expected to be unchanged');
7997
}
@@ -93,7 +111,7 @@ public function testCreatedNotNew() {
93111
$entity = new Entity(['name' => 'Foo']);
94112
$entity->isNew(false);
95113

96-
$return = $this->Behavior->beforeSave($event, $entity);
114+
$return = $this->Behavior->handleEvent($event, $entity);
97115
$this->assertTrue($return, 'Handle Event is expected to always return true');
98116
$this->assertNull($entity->created, 'Created timestamp is expected to be untouched if the entity is not new');
99117
}
@@ -113,7 +131,7 @@ public function testModifiedAbsent() {
113131
$entity = new Entity(['name' => 'Foo']);
114132
$entity->isNew(false);
115133

116-
$return = $this->Behavior->beforeSave($event, $entity);
134+
$return = $this->Behavior->handleEvent($event, $entity);
117135
$this->assertTrue($return, 'Handle Event is expected to always return true');
118136
$this->assertSame($ts, $entity->modified, 'Modified timestamp is expected to be the mocked value');
119137
}
@@ -135,7 +153,7 @@ public function testModifiedPresent() {
135153
$entity->clean();
136154
$entity->isNew(false);
137155

138-
$return = $this->Behavior->beforeSave($event, $entity);
156+
$return = $this->Behavior->handleEvent($event, $entity);
139157
$this->assertTrue($return, 'Handle Event is expected to always return true');
140158
$this->assertSame($ts, $entity->modified, 'Modified timestamp is expected to be updated');
141159
}

0 commit comments

Comments
 (0)