Skip to content

Commit 6342410

Browse files
committed
Add events to the attaching/detaching methods.
- Fix #151
1 parent d4c0242 commit 6342410

File tree

6 files changed

+423
-7
lines changed

6 files changed

+423
-7
lines changed

src/Traits/LaratrustHasEvents.php

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
<?php
2+
3+
namespace Laratrust\Traits;
4+
5+
trait LaratrustHasEvents
6+
{
7+
/**
8+
* Fire the given event for the model.
9+
*
10+
* @param string $event
11+
* @param array $payload
12+
* @return mixed
13+
*/
14+
protected function fireLaratrustEvent($event, array $payload)
15+
{
16+
if (! isset(static::$dispatcher)) {
17+
return true;
18+
}
19+
20+
return static::$dispatcher->fire(
21+
"laratrust.{$event}: ".static::class,
22+
$payload
23+
);
24+
}
25+
26+
/**
27+
* Register a laratrust event with the dispatcher.
28+
*
29+
* @param string $event
30+
* @param \Closure|string $callback
31+
* @return void
32+
*/
33+
public static function registerLaratrustEvent($event, $callback)
34+
{
35+
if (isset(static::$dispatcher)) {
36+
$name = static::class;
37+
38+
static::$dispatcher->listen("laratrust.{$event}: {$name}", $callback);
39+
}
40+
}
41+
42+
/**
43+
* Register a role attached laratrust event with the dispatcher.
44+
*
45+
* @param \Closure|string $callback
46+
* @return void
47+
*/
48+
public static function roleAttached($callback)
49+
{
50+
static::registerLaratrustEvent('role.attached', $callback);
51+
}
52+
53+
/**
54+
* Register a role detached laratrust event with the dispatcher.
55+
*
56+
* @param \Closure|string $callback
57+
* @return void
58+
*/
59+
public static function roleDetached($callback)
60+
{
61+
static::registerLaratrustEvent('role.detached', $callback);
62+
}
63+
64+
/**
65+
* Register a permission attached laratrust event with the dispatcher.
66+
*
67+
* @param \Closure|string $callback
68+
* @return void
69+
*/
70+
public static function permissionAttached($callback)
71+
{
72+
static::registerLaratrustEvent('permission.attached', $callback);
73+
}
74+
75+
/**
76+
* Register a permission detached laratrust event with the dispatcher.
77+
*
78+
* @param \Closure|string $callback
79+
* @return void
80+
*/
81+
public static function permissionDetached($callback)
82+
{
83+
static::registerLaratrustEvent('permission.detached', $callback);
84+
}
85+
86+
/**
87+
* Register a role synced laratrust event with the dispatcher.
88+
*
89+
* @param \Closure|string $callback
90+
* @return void
91+
*/
92+
public static function roleSynced($callback)
93+
{
94+
static::registerLaratrustEvent('role.synced', $callback);
95+
}
96+
97+
/**
98+
* Register a permission synced laratrust event with the dispatcher.
99+
*
100+
* @param \Closure|string $callback
101+
* @return void
102+
*/
103+
public static function permissionSynced($callback)
104+
{
105+
static::registerLaratrustEvent('permission.synced', $callback);
106+
}
107+
}

src/Traits/LaratrustRoleTrait.php

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
trait LaratrustRoleTrait
1818
{
1919
use LaratrustDynamicUserRelationsCalls;
20+
use LaratrustHasEvents;
2021

2122
/**
2223
* Tries to return all the cached permissions of the role.
@@ -147,9 +148,15 @@ public function hasPermission($permission, $requireAll = false)
147148
*/
148149
public function syncPermissions($permissions)
149150
{
150-
// If the permissions is empty it will delete all associations.
151+
$mappedPermissions = [];
152+
153+
foreach ($permissions as $permission) {
154+
$mappedPermissions[] = Helper::getIdFor($permission, $permission);
155+
}
156+
151157
$changes = $this->permissions()->sync($permissions);
152158
$this->flushCache();
159+
$this->fireLaratrustEvent("permission.synced", [$this, $changes]);
153160

154161
return $this;
155162
}
@@ -162,8 +169,11 @@ public function syncPermissions($permissions)
162169
*/
163170
public function attachPermission($permission)
164171
{
165-
$this->permissions()->attach(Helper::getIdFor($permission, 'permission'));
172+
$permission = Helper::getIdFor($permission, 'permission');
173+
174+
$this->permissions()->attach($permission);
166175
$this->flushCache();
176+
$this->fireLaratrustEvent("permission.attached", [$this, $permission]);
167177

168178
return $this;
169179
}
@@ -176,8 +186,11 @@ public function attachPermission($permission)
176186
*/
177187
public function detachPermission($permission)
178188
{
179-
$this->permissions()->detach(Helper::getIdFor($permission, 'permission'));
189+
$permission = Helper::getIdFor($permission, 'permission');
190+
191+
$this->permissions()->detach($permission);
180192
$this->flushCache();
193+
$this->fireLaratrustEvent("permission.detached", [$this, $permission]);
181194

182195
return $this;
183196
}

src/Traits/LaratrustUserTrait.php

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
trait LaratrustUserTrait
2020
{
21+
use LaratrustHasEvents;
22+
2123
/**
2224
* Tries to return all the cached roles of the user.
2325
* If it can't bring the roles from the cache,
@@ -365,6 +367,7 @@ private function attachModel($relationship, $objectType, $object, $team)
365367
$attributes
366368
);
367369
$this->flushCache();
370+
$this->fireLaratrustEvent("{$objectType}.attached", [$this, $object, $team]);
368371

369372
return $this;
370373
}
@@ -393,11 +396,11 @@ private function detachModel($relationship, $objectType, $object, $team)
393396
);
394397
}
395398

396-
$relationshipQuery->detach(
397-
Helper::getIdFor($object, $objectType)
398-
);
399+
$object = Helper::getIdFor($object, $objectType);
400+
$relationshipQuery->detach($object);
399401

400402
$this->flushCache();
403+
$this->fireLaratrustEvent("{$objectType}.detached", [$this, $object, $team]);
401404

402405
return $this;
403406
}
@@ -422,9 +425,10 @@ private function syncModels($relationship, $objectType, $objects, $team, $detach
422425
$relationshipToSync->wherePivot(Helper::teamForeignKey(), $team);
423426
}
424427

425-
$relationshipToSync->sync($mappedObjects, $detaching);
428+
$result = $relationshipToSync->sync($mappedObjects, $detaching);
426429

427430
$this->flushCache();
431+
$this->fireLaratrustEvent("{$objectType}.synced", [$this, $result, $team]);
428432

429433
return $this;
430434
}

tests/LaratrustEventsTestCase.php

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
<?php
2+
3+
namespace Laratrust\Tests;
4+
5+
use Mockery as m;
6+
7+
class LaratrustEventsTestCase extends LaratrustTestCase
8+
{
9+
protected $dispatcher;
10+
11+
public function setUp()
12+
{
13+
parent::setUp();
14+
15+
$this->migrate();
16+
$this->dispatcher = m::mock('\Illuminate\Events\Dispatcher')->makePartial();
17+
$this->app['config']->set('laratrust.use_teams', true);
18+
}
19+
20+
/**
21+
* Listen to a Laratrust event.
22+
*
23+
* @param string $event
24+
* @return void
25+
*/
26+
protected function listenTo($event, $modelClass)
27+
{
28+
$method = \Illuminate\Support\Str::camel(str_replace('.', ' ', $event));
29+
30+
$modelClass::{$method}(function ($user, $roleId) {
31+
return 'test';
32+
});
33+
}
34+
35+
/**
36+
* Assert that the dispatcher has listeners for the given event.
37+
*
38+
* @param string $event
39+
* @return void
40+
*/
41+
protected function assertHasListenersFor($event, $modelClass)
42+
{
43+
$eventName = "laratrust.{$event}: {$modelClass}";
44+
$dispatcher = $modelClass::getEventDispatcher();
45+
46+
$this->assertTrue($dispatcher->hasListeners($eventName));
47+
$this->assertCount(1, $dispatcher->getListeners($eventName));
48+
$this->assertEquals('test', $dispatcher->fire($eventName, ['user', 'an_id', null])[0]);
49+
}
50+
51+
/**
52+
* Assert the dispatcher fires the fire event with the given data.
53+
*
54+
* @param string $event
55+
* @param array $payload
56+
* @param string $model
57+
* @return void
58+
*/
59+
protected function dispatcherShouldFire($event, array $payload, $modelClass)
60+
{
61+
$this->dispatcher->shouldReceive('fire')
62+
->with(
63+
"laratrust.{$event}: {$modelClass}",
64+
$payload
65+
)
66+
->andReturn(null)
67+
->once()->ordered();
68+
}
69+
}

tests/LaratrustRoleEventsTest.php

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
<?php
2+
3+
namespace Laratrust\Tests;
4+
5+
use Mockery as m;
6+
use Laratrust\Tests\Models\Role;
7+
use Laratrust\Tests\Models\User;
8+
use Laratrust\Tests\LaratrustTestCase;
9+
use Laratrust\Tests\Models\Permission;
10+
11+
class LaratrustRoleEventsTest extends LaratrustEventsTestCase
12+
{
13+
protected $role;
14+
15+
public function setUp()
16+
{
17+
parent::setUp();
18+
$this->role = Role::create(['name' => 'role']);
19+
20+
}
21+
22+
public function testCanListenToThePermissionAttachedEvent()
23+
{
24+
$this->listenTo('permission.attached', Role::class);
25+
26+
$this->assertHasListenersFor('permission.attached', Role::class);
27+
}
28+
29+
public function testCanListenToThePermissionDetachedEvent()
30+
{
31+
$this->listenTo('permission.detached', Role::class);
32+
33+
$this->assertHasListenersFor('permission.detached', Role::class);
34+
}
35+
36+
public function testCanListenToThePermissionSyncedEvent()
37+
{
38+
$this->listenTo('permission.synced', Role::class);
39+
40+
$this->assertHasListenersFor('permission.synced', Role::class);
41+
}
42+
43+
public function testAnEventIsFiredWhenPermissionIsAttachedToRole()
44+
{
45+
$permission = Permission::create(['name' => 'permission']);
46+
47+
Role::setEventDispatcher($this->dispatcher);
48+
49+
$this->dispatcherShouldFire('permission.attached', [$this->role, $permission->id], Role::class);
50+
51+
$this->role->attachPermission($permission);
52+
}
53+
54+
public function testAnEventIsFiredWhenPermissionIsDetachedFromRole()
55+
{
56+
$permission = Permission::create(['name' => 'permission']);
57+
$this->role->attachPermission($permission);
58+
59+
Role::setEventDispatcher($this->dispatcher);
60+
61+
$this->dispatcherShouldFire('permission.detached', [$this->role, $permission->id], Role::class);
62+
63+
$this->role->detachPermission($permission);
64+
}
65+
66+
public function testAnEventIsFiredWhenPermissionsAreSynced()
67+
{
68+
$permission = Permission::create(['name' => 'permission']);
69+
$this->role->attachPermission($permission);
70+
71+
Role::setEventDispatcher($this->dispatcher);
72+
73+
$this->dispatcherShouldFire('permission.synced', [
74+
$this->role,
75+
[
76+
'attached' => [], 'detached' => [$permission->id], 'updated' => [],
77+
]
78+
], Role::class);
79+
80+
$this->role->syncPermissions([]);
81+
}
82+
}

0 commit comments

Comments
 (0)