Skip to content

Commit ceeeb56

Browse files
authored
Merge pull request #97 from siamak2/events
[2.1.0] Events
2 parents d30ef57 + c3ef15a commit ceeeb56

27 files changed

+1068
-35
lines changed

CHANGELOG.md

+7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# Release Notes
22

3+
## v2.1.0
4+
5+
### Added
6+
7+
* Added [events](README.md#events) for metas.
8+
* Added `isMetaDirty` method.
9+
310
## v2.0.1
411

512
### Changes

README.md

+74-1
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ Laravel meta 2 has some backward incompatible changes that listed below:
6666

6767
#### Migration Table Schema
6868

69+
Each model needs its own meta table.
70+
6971
This is an example migration. you need change parts of it.
7072

7173
In this example we assume you have a model named `Post`.
@@ -344,7 +346,7 @@ $post->getMeta(['content', 'views'],'none');// result if the metas are missing:
344346
$post->getMeta(['content', 'views']);// result if the metas are missing: ['content'=>null,'views'=>null]
345347
```
346348

347-
#### Disable fluent access
349+
#### Disable Fluent Access
348350

349351
If you don't want to access metas in fluent way, you can disable it by adding following property to your model:
350352

@@ -408,3 +410,74 @@ You can also use it on eloquent relations.
408410
/* Post model */
409411
public $hideMeta = true; // Do not add metas to array
410412
```
413+
414+
## Events
415+
416+
Laravel meta dispatches several events, allowing you to hook into the following events: `metaCreating`, `metaCreated`, `metaSaving`, `metaSaved`, `metaUpdating`, `metaUpdated`, `metaDeleting` and `metaDeleted`. Listeners should expect two parameters, first an instance of the model and second, name of the meta that event occurred for it. To enable events you need to add `HasMetaEvents` trait to your model:
417+
418+
```php
419+
use Kodeine\Metable\Metable;
420+
use Kodeine\Metable\HasMetaEvents;
421+
use Illuminate\Database\Eloquent\Model;
422+
423+
class User extends Model
424+
{
425+
use Metable,HasMetaEvents;
426+
}
427+
```
428+
429+
After that, you can listen for events the [same way](https://laravel.com/docs/master/eloquent#events) you do for models.
430+
431+
> If you `return false;` in listener of any event ending with `ing`, that operation will be aborted.
432+
433+
There are 3 ways to listen for events:
434+
435+
#### 1. By Defining `$dispatchesEvents` Property
436+
437+
```php
438+
use App\Events\UserMetaSaved;
439+
use Kodeine\Metable\Metable;
440+
use Kodeine\Metable\HasMetaEvents;
441+
use Illuminate\Database\Eloquent\Model;
442+
443+
class User extends Model
444+
{
445+
use Metable,HasMetaEvents;
446+
447+
protected $dispatchesEvents = [
448+
'metaSaved' => UserMetaSaved::class,
449+
];
450+
}
451+
```
452+
453+
#### 2. [Using Closures](https://laravel.com/docs/master/eloquent#events-using-closures)
454+
455+
```php
456+
use Kodeine\Metable\Metable;
457+
use Kodeine\Metable\HasMetaEvents;
458+
use Illuminate\Database\Eloquent\Model;
459+
460+
class User extends Model
461+
{
462+
use Metable,HasMetaEvents;
463+
464+
protected static function booted()
465+
{
466+
static::metaCreated(function ($user, $meta) {
467+
//
468+
});
469+
}
470+
}
471+
```
472+
473+
#### 3. [Observers](https://laravel.com/docs/master/eloquent#observers)
474+
475+
```php
476+
class UserObserver
477+
{
478+
public function metaCreated(User $user,$meta)
479+
{
480+
//
481+
}
482+
}
483+
```

src/Kodeine/Metable/HasMetaEvents.php

+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
<?php
2+
3+
namespace Kodeine\Metable;
4+
5+
trait HasMetaEvents
6+
{
7+
/**
8+
* @param $event
9+
* @param $metaName
10+
* @param bool $halt
11+
* @return mixed
12+
*/
13+
protected function __fireMetaEvent($event, $metaName, bool $halt = true) {
14+
if ( ! isset( static::$dispatcher ) ) {
15+
return true;
16+
}
17+
// First, we will get the proper method to call on the event dispatcher, and then we
18+
// will attempt to fire a custom, object based event for the given event. If that
19+
// returns a result we can return that result, or we'll call the string events.
20+
$method = $halt ? 'until' : 'dispatch';
21+
$result = $this->filterModelEventResults(
22+
$this->fireCustomMetaEvent( $event, $method, $metaName )
23+
);
24+
25+
if ( $result === false ) {
26+
return false;
27+
}
28+
29+
return ! empty( $result ) ? $result : static::$dispatcher->{$method}(
30+
"eloquent.{$event}: " . static::class, [
31+
$this,
32+
$metaName,
33+
]
34+
);
35+
}
36+
37+
/**
38+
* @param $event
39+
* @param $method
40+
* @param $params
41+
* @return mixed|null
42+
*/
43+
protected function fireCustomMetaEvent($event, $method, $params) {
44+
if ( ! isset( $this->dispatchesEvents[$event] ) ) {
45+
return;
46+
}
47+
return static::$dispatcher->$method( new $this->dispatchesEvents[$event]( $this, $params ) );
48+
}
49+
50+
protected function initializeHasMetaEvents() {
51+
$this->observables = array_merge( $this->observables, [
52+
'metaCreating',
53+
'metaCreated',
54+
'metaSaving',
55+
'metaSaved',
56+
'metaUpdating',
57+
'metaUpdated',
58+
'metaDeleting',
59+
'metaDeleted',
60+
] );
61+
$this->observables = array_unique( $this->observables );
62+
}
63+
64+
public static function metaCreating($callback) {
65+
static::registerModelEvent( 'metaCreating', $callback );
66+
}
67+
68+
public static function metaCreated($callback) {
69+
static::registerModelEvent( 'metaCreated', $callback );
70+
}
71+
72+
public static function metaSaving($callback) {
73+
static::registerModelEvent( 'metaSaving', $callback );
74+
}
75+
76+
public static function metaSaved($callback) {
77+
static::registerModelEvent( 'metaSaved', $callback );
78+
}
79+
80+
public static function metaUpdating($callback) {
81+
static::registerModelEvent( 'metaUpdating', $callback );
82+
}
83+
84+
public static function metaUpdated($callback) {
85+
static::registerModelEvent( 'metaUpdated', $callback );
86+
}
87+
88+
public static function metaDeleting($callback) {
89+
static::registerModelEvent( 'metaDeleting', $callback );
90+
}
91+
92+
public static function metaDeleted($callback) {
93+
static::registerModelEvent( 'metaDeleted', $callback );
94+
}
95+
}

src/Kodeine/Metable/Metable.php

+67-1
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,41 @@ protected function hasMetaArray($keys): bool {
118118
return true;
119119
}
120120

121+
/**
122+
* Determine if the meta or any of the given metas have been modified.
123+
*
124+
* @param array|string|null $metas
125+
* @return bool
126+
*/
127+
public function isMetaDirty(...$metas): bool {
128+
if ( empty( $metas ) ) {
129+
foreach ($this->getMetaData() as $meta) {
130+
if ( $meta->isDirty() ) {
131+
return true;
132+
}
133+
}
134+
return false;
135+
}
136+
if ( is_array( $metas[0] ) ) {
137+
$metas = $metas[0];
138+
}
139+
elseif ( is_string( $metas[0] ) && preg_match( '/[,|]/is', $metas[0] ) ) {
140+
$metas = preg_split( '/ ?[,|] ?/', $metas[0] );
141+
}
142+
143+
foreach ($metas as $meta) {
144+
if ( $this->getMetaData()->has( $meta ) ) {
145+
if ( $this->getMetaData()[$meta]->isDirty() ) {
146+
return true;
147+
}
148+
if ( $this->getMetaData()[$meta]->isMarkedForDeletion() ) {
149+
return true;
150+
}
151+
}
152+
}
153+
return false;
154+
}
155+
121156
/**
122157
* Unset Meta Data functions
123158
* -------------------------.
@@ -269,19 +304,50 @@ public function saveMeta() {
269304
$meta->setTable( $this->getMetaTable() );
270305

271306
if ( $meta->isMarkedForDeletion() ) {
307+
if ( $meta->exists ) {
308+
if ( $this->fireMetaEvent( 'deleting', $meta->key ) === false ) {
309+
continue;
310+
}
311+
}
272312
$meta->delete();
273313
unset( $this->getMetaData()[$meta->key] );
314+
$this->fireMetaEvent( 'deleted', $meta->key, false );
274315
continue;
275316
}
276317

277318
if ( $meta->isDirty() ) {
319+
if ( $this->fireMetaEvent( 'saving', $meta->key ) === false ) {
320+
continue;
321+
}
322+
if ( $meta->exists ) {
323+
if ( $this->fireMetaEvent( 'updating', $meta->key ) === false ) {
324+
continue;
325+
}
326+
$nextEvent = 'updated';
327+
}
328+
else {
329+
if ( $this->fireMetaEvent( 'creating', $meta->key ) === false ) {
330+
continue;
331+
}
332+
$nextEvent = 'created';
333+
}
278334
// set meta and model relation id's into meta table.
279335
$meta->setAttribute( $this->getMetaKeyName(), $this->getKey() );
280-
$meta->save();
336+
if ( $meta->save() ) {
337+
$this->fireMetaEvent( $nextEvent, $meta->key, false );
338+
$this->fireMetaEvent( 'saved', $meta->key, false );
339+
}
281340
}
282341
}
283342
}
284343

344+
protected function fireMetaEvent($event, $metaName, bool $halt = true) {
345+
if ( method_exists( $this, '__fireMetaEvent' ) ) {
346+
return $this->__fireMetaEvent( 'meta' . Str::ucfirst( $event ), $metaName, $halt );
347+
}
348+
return true;
349+
}
350+
285351
public function getMetaData() {
286352
if ( is_null( $this->__metaData ) ) {
287353

tests/Events/BaseEventTest.php

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
namespace Kodeine\Metable\Tests\Events;
4+
5+
use Kodeine\Metable\Tests\Models\EventTest;
6+
7+
class BaseEventTest
8+
{
9+
/**
10+
* @var EventTest
11+
*/
12+
public $model;
13+
public $meta;
14+
15+
public function __construct(EventTest $model, $meta) {
16+
$this->model = $model;
17+
$this->meta = $meta;
18+
}
19+
}

tests/Events/MetaCreatedTestEvent.php

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
namespace Kodeine\Metable\Tests\Events;
4+
5+
6+
class MetaCreatedTestEvent extends BaseEventTest
7+
{
8+
9+
}
+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
namespace Kodeine\Metable\Tests\Events;
4+
5+
6+
class MetaCreatingTestEvent extends BaseEventTest
7+
{
8+
9+
}

tests/Events/MetaDeletedTestEvent.php

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
namespace Kodeine\Metable\Tests\Events;
4+
5+
6+
class MetaDeletedTestEvent extends BaseEventTest
7+
{
8+
9+
}
+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
namespace Kodeine\Metable\Tests\Events;
4+
5+
6+
class MetaDeletingTestEvent extends BaseEventTest
7+
{
8+
9+
}

tests/Events/MetaSavedTestEvent.php

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
namespace Kodeine\Metable\Tests\Events;
4+
5+
6+
class MetaSavedTestEvent extends BaseEventTest
7+
{
8+
9+
}

tests/Events/MetaSavingTestEvent.php

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
namespace Kodeine\Metable\Tests\Events;
4+
5+
6+
class MetaSavingTestEvent extends BaseEventTest
7+
{
8+
9+
}

tests/Events/MetaUpdatedTestEvent.php

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
namespace Kodeine\Metable\Tests\Events;
4+
5+
6+
class MetaUpdatedTestEvent extends BaseEventTest
7+
{
8+
9+
}

0 commit comments

Comments
 (0)