Skip to content

Commit

Permalink
Merge pull request #97 from siamak2/events
Browse files Browse the repository at this point in the history
[2.1.0] Events
  • Loading branch information
kodeine authored Jun 9, 2022
2 parents d30ef57 + c3ef15a commit ceeeb56
Show file tree
Hide file tree
Showing 27 changed files with 1,068 additions and 35 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Release Notes

## v2.1.0

### Added

* Added [events](README.md#events) for metas.
* Added `isMetaDirty` method.

## v2.0.1

### Changes
Expand Down
75 changes: 74 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ Laravel meta 2 has some backward incompatible changes that listed below:

#### Migration Table Schema

Each model needs its own meta table.

This is an example migration. you need change parts of it.

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

#### Disable fluent access
#### Disable Fluent Access

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

Expand Down Expand Up @@ -408,3 +410,74 @@ You can also use it on eloquent relations.
/* Post model */
public $hideMeta = true; // Do not add metas to array
```

## Events

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:

```php
use Kodeine\Metable\Metable;
use Kodeine\Metable\HasMetaEvents;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
use Metable,HasMetaEvents;
}
```

After that, you can listen for events the [same way](https://laravel.com/docs/master/eloquent#events) you do for models.

> If you `return false;` in listener of any event ending with `ing`, that operation will be aborted.
There are 3 ways to listen for events:

#### 1. By Defining `$dispatchesEvents` Property

```php
use App\Events\UserMetaSaved;
use Kodeine\Metable\Metable;
use Kodeine\Metable\HasMetaEvents;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
use Metable,HasMetaEvents;

protected $dispatchesEvents = [
'metaSaved' => UserMetaSaved::class,
];
}
```

#### 2. [Using Closures](https://laravel.com/docs/master/eloquent#events-using-closures)

```php
use Kodeine\Metable\Metable;
use Kodeine\Metable\HasMetaEvents;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
use Metable,HasMetaEvents;

protected static function booted()
{
static::metaCreated(function ($user, $meta) {
//
});
}
}
```

#### 3. [Observers](https://laravel.com/docs/master/eloquent#observers)

```php
class UserObserver
{
public function metaCreated(User $user,$meta)
{
//
}
}
```
95 changes: 95 additions & 0 deletions src/Kodeine/Metable/HasMetaEvents.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
<?php

namespace Kodeine\Metable;

trait HasMetaEvents
{
/**
* @param $event
* @param $metaName
* @param bool $halt
* @return mixed
*/
protected function __fireMetaEvent($event, $metaName, bool $halt = true) {
if ( ! isset( static::$dispatcher ) ) {
return true;
}
// First, we will get the proper method to call on the event dispatcher, and then we
// will attempt to fire a custom, object based event for the given event. If that
// returns a result we can return that result, or we'll call the string events.
$method = $halt ? 'until' : 'dispatch';
$result = $this->filterModelEventResults(
$this->fireCustomMetaEvent( $event, $method, $metaName )
);

if ( $result === false ) {
return false;
}

return ! empty( $result ) ? $result : static::$dispatcher->{$method}(
"eloquent.{$event}: " . static::class, [
$this,
$metaName,
]
);
}

/**
* @param $event
* @param $method
* @param $params
* @return mixed|null
*/
protected function fireCustomMetaEvent($event, $method, $params) {
if ( ! isset( $this->dispatchesEvents[$event] ) ) {
return;
}
return static::$dispatcher->$method( new $this->dispatchesEvents[$event]( $this, $params ) );
}

protected function initializeHasMetaEvents() {
$this->observables = array_merge( $this->observables, [
'metaCreating',
'metaCreated',
'metaSaving',
'metaSaved',
'metaUpdating',
'metaUpdated',
'metaDeleting',
'metaDeleted',
] );
$this->observables = array_unique( $this->observables );
}

public static function metaCreating($callback) {
static::registerModelEvent( 'metaCreating', $callback );
}

public static function metaCreated($callback) {
static::registerModelEvent( 'metaCreated', $callback );
}

public static function metaSaving($callback) {
static::registerModelEvent( 'metaSaving', $callback );
}

public static function metaSaved($callback) {
static::registerModelEvent( 'metaSaved', $callback );
}

public static function metaUpdating($callback) {
static::registerModelEvent( 'metaUpdating', $callback );
}

public static function metaUpdated($callback) {
static::registerModelEvent( 'metaUpdated', $callback );
}

public static function metaDeleting($callback) {
static::registerModelEvent( 'metaDeleting', $callback );
}

public static function metaDeleted($callback) {
static::registerModelEvent( 'metaDeleted', $callback );
}
}
68 changes: 67 additions & 1 deletion src/Kodeine/Metable/Metable.php
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,41 @@ protected function hasMetaArray($keys): bool {
return true;
}

/**
* Determine if the meta or any of the given metas have been modified.
*
* @param array|string|null $metas
* @return bool
*/
public function isMetaDirty(...$metas): bool {
if ( empty( $metas ) ) {
foreach ($this->getMetaData() as $meta) {
if ( $meta->isDirty() ) {
return true;
}
}
return false;
}
if ( is_array( $metas[0] ) ) {
$metas = $metas[0];
}
elseif ( is_string( $metas[0] ) && preg_match( '/[,|]/is', $metas[0] ) ) {
$metas = preg_split( '/ ?[,|] ?/', $metas[0] );
}

foreach ($metas as $meta) {
if ( $this->getMetaData()->has( $meta ) ) {
if ( $this->getMetaData()[$meta]->isDirty() ) {
return true;
}
if ( $this->getMetaData()[$meta]->isMarkedForDeletion() ) {
return true;
}
}
}
return false;
}

/**
* Unset Meta Data functions
* -------------------------.
Expand Down Expand Up @@ -269,19 +304,50 @@ public function saveMeta() {
$meta->setTable( $this->getMetaTable() );

if ( $meta->isMarkedForDeletion() ) {
if ( $meta->exists ) {
if ( $this->fireMetaEvent( 'deleting', $meta->key ) === false ) {
continue;
}
}
$meta->delete();
unset( $this->getMetaData()[$meta->key] );
$this->fireMetaEvent( 'deleted', $meta->key, false );
continue;
}

if ( $meta->isDirty() ) {
if ( $this->fireMetaEvent( 'saving', $meta->key ) === false ) {
continue;
}
if ( $meta->exists ) {
if ( $this->fireMetaEvent( 'updating', $meta->key ) === false ) {
continue;
}
$nextEvent = 'updated';
}
else {
if ( $this->fireMetaEvent( 'creating', $meta->key ) === false ) {
continue;
}
$nextEvent = 'created';
}
// set meta and model relation id's into meta table.
$meta->setAttribute( $this->getMetaKeyName(), $this->getKey() );
$meta->save();
if ( $meta->save() ) {
$this->fireMetaEvent( $nextEvent, $meta->key, false );
$this->fireMetaEvent( 'saved', $meta->key, false );
}
}
}
}

protected function fireMetaEvent($event, $metaName, bool $halt = true) {
if ( method_exists( $this, '__fireMetaEvent' ) ) {
return $this->__fireMetaEvent( 'meta' . Str::ucfirst( $event ), $metaName, $halt );
}
return true;
}

public function getMetaData() {
if ( is_null( $this->__metaData ) ) {

Expand Down
19 changes: 19 additions & 0 deletions tests/Events/BaseEventTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

namespace Kodeine\Metable\Tests\Events;

use Kodeine\Metable\Tests\Models\EventTest;

class BaseEventTest
{
/**
* @var EventTest
*/
public $model;
public $meta;

public function __construct(EventTest $model, $meta) {
$this->model = $model;
$this->meta = $meta;
}
}
9 changes: 9 additions & 0 deletions tests/Events/MetaCreatedTestEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

namespace Kodeine\Metable\Tests\Events;


class MetaCreatedTestEvent extends BaseEventTest
{

}
9 changes: 9 additions & 0 deletions tests/Events/MetaCreatingTestEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

namespace Kodeine\Metable\Tests\Events;


class MetaCreatingTestEvent extends BaseEventTest
{

}
9 changes: 9 additions & 0 deletions tests/Events/MetaDeletedTestEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

namespace Kodeine\Metable\Tests\Events;


class MetaDeletedTestEvent extends BaseEventTest
{

}
9 changes: 9 additions & 0 deletions tests/Events/MetaDeletingTestEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

namespace Kodeine\Metable\Tests\Events;


class MetaDeletingTestEvent extends BaseEventTest
{

}
9 changes: 9 additions & 0 deletions tests/Events/MetaSavedTestEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

namespace Kodeine\Metable\Tests\Events;


class MetaSavedTestEvent extends BaseEventTest
{

}
9 changes: 9 additions & 0 deletions tests/Events/MetaSavingTestEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

namespace Kodeine\Metable\Tests\Events;


class MetaSavingTestEvent extends BaseEventTest
{

}
9 changes: 9 additions & 0 deletions tests/Events/MetaUpdatedTestEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

namespace Kodeine\Metable\Tests\Events;


class MetaUpdatedTestEvent extends BaseEventTest
{

}
Loading

0 comments on commit ceeeb56

Please sign in to comment.