Skip to content

Instantly share code, notes, and snippets.

@TsuiAnthonYVR
Created July 19, 2017 13:07
Show Gist options
  • Save TsuiAnthonYVR/1435e18ee76f095e2c348affa1dc060b to your computer and use it in GitHub Desktop.
Save TsuiAnthonYVR/1435e18ee76f095e2c348affa1dc060b to your computer and use it in GitHub Desktop.
How to get Laravel to fire model attach/detach events
<?php namespace App\Relations;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
class BelongsToMany extends \Illuminate\Database\Eloquent\Relations\BelongsToMany {
/**
* Attach a model to the parent.
*
* @param mixed $id
* @param array $attributes
* @param bool $touch
* @return void
*/
public function attach($id, array $attributes = array(), $touch = true) {
// Process the actual functionality first.
parent::attach($id, $attributes, $touch);
if ($id instanceof Model) {
$id = $id->getKey();
}
// Fire an event
$parentId = $this->parent->id;
$childId = $id;
$pivotInfo = [
// e.g. "user_team"
'table' => $this->table,
// e.g. "user_id" => 123
$this->foreignKey => $this->parent->id,
// e.g. "team_id" => 456
$this->otherKey => $id,
];
// Fire the event.
\Event::fire(new \App\Events\PivotWasCreated($pivotInfo));
}
/**
* Detach models from the relationship.
*
* @param int|array $ids
* @param bool $touch
* @return int
*/
public function detach($ids = array(), $touch = true) {
// Process the actual functionality first.
$ids = (is_array($ids))?:[$ids];
$result = parent::detach($ids, $touch);
// Fire an event for each deleted pivot.
foreach($ids as $id) {
$parentId = $this->parent->id;
$childId = $id;
$pivotInfo = [
// e.g. "user_team"
'table' => $this->table,
// e.g. "user_id" => 123
$this->foreignKey => $this->parent->id,
// e.g. "team_id" => 456
$this->otherKey => $id,
];
\Event::fire(new \App\Events\PivotWasDeleted($pivotInfo));
}
return $result;
}
}
<?php namespace App\Handlers\Event;
class HandlePivotEvent {
/**
* handlePivotEvent function.
*
* @param \App\Events\Event $pivotEvent
*/
public function handle(\App\Events\Event $pivotEvent)
{
// Determine whether this is an attach or detach event.
switch (get_class($pivotEvent)) {
case 'App\Events\PivotWasCreated':
$eventName = 'attach';
break;
case 'App\Events\PivotWasDeleted':
$eventName = 'detach';
break;
default:
// Unknown event
return;
}
// Get a list of all attributes that are foreign keys.
$modelKeys = $this->extractModelKeys($pivotEvent->pivotInfo);
// do your useful work here
}
/**
* extractModelKeys function.
*
* @param array $fieldNames
*
* @return array
*/
protected function extractModelKeys(array $fieldNames)
{
$modelKeys = [];
foreach ($fieldNames as $fieldName => $value) {
if (preg_match('/([^_]+)_id/', $fieldName, $matches)) {
// This field is a key
$modelKeys[strtolower($matches[1])] = $value;
}
}
// Ensure our model keys are always in the same order.
ksort($modelKeys);
return $modelKeys;
} // function extractModelKeys
}
<?php namespace app\Traits;
/**
* ManagedCacheTrait Trait.
*
* Provides managed cache in the parent model.
*
*/
trait PivotTrait
{
/**
* Define a many-to-many relationship.
*
* @param string $related
* @param string $table
* @param string $foreignKey
* @param string $otherKey
* @param string $relation
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function belongsToMany($related, $table = null, $foreignKey = null, $otherKey = null, $relation = null, $farKey = null)
{
// copied from https://github.com/illuminate/database/blob/master/Eloquent/Model.php#L963
if (is_null($relation)) {
$relation = $this->getBelongsToManyCaller();
}
$foreignKey = $foreignKey ?: $this->getForeignKey();
$instance = new $related;
if ($farKey) {
$instance = $instance->setKeyName($farKey);
}
$otherKey = $otherKey ?: $instance->getForeignKey();
if (is_null($table)) {
$table = $this->joiningTable($related);
}
$query = $instance->newQuery();
return new \App\Relations\BelongsToMany($query, $this, $table, $foreignKey, $otherKey, $relation);
}
}
<?php namespace App\Events;
use App\Events\Event;
use Illuminate\Queue\SerializesModels;
class PivotWasCreated extends Event {
use SerializesModels;
public $pivotInfo;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct(array $pivotInfo) {
$this->pivotInfo = $pivotInfo;
}
} // PivotWasCreated Event
<?php namespace App\Events;
use App\Events\Event;
use Illuminate\Queue\SerializesModels;
class PivotWasDeleted extends Event {
use SerializesModels;
public $pivotInfo;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct(array $pivotInfo) {
$this->pivotInfo = $pivotInfo;
}
} // PivotWasDeleted Event
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment