-
Notifications
You must be signed in to change notification settings - Fork 24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Trait method collision with SoftDeletes #11
Comments
@theoxuan Is there any ways can you share code with me? |
Yes, but what I mean is that the This is Laravel's SoftDeletes.php <?php
namespace Illuminate\Database\Eloquent;
trait SoftDeletes
{
//omitted
/**
* Restore a soft-deleted model instance.
*
* @return bool|null
*/
public function restore()
{
// If the restoring event does not return false, we will proceed with this
// restore operation. Otherwise, we bail out so the developer will stop
// the restore totally. We will clear the deleted timestamp and save.
if ($this->fireModelEvent('restoring') === false) {
return false;
}
$this->{$this->getDeletedAtColumn()} = null;
// Once we have saved the model, we will fire the "restored" event so this
// developer will do anything they need to after a restore operation is
// totally finished. Then we will return the result of the save call.
$this->exists = true;
$result = $this->save();
$this->fireModelEvent('restored', false);
return $result;
}
//omitted
/**
* Determine if the model is currently force deleting.
*
* @return bool
*/
public function isForceDeleting()
{
return $this->forceDeleting;
}
//omitted
} And here is the provided trait NtrustUserTrait.php <?php namespace Klaravel\Ntrust\Traits;
use Illuminate\Cache\TaggableStore;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Config;
use InvalidArgumentException;
trait NtrustUserTrait
{
//omitted
public function delete(array $options = [])
{ //soft or hard
parent::delete($options);
if(Cache::getStore() instanceof TaggableStore) {
Cache::tags(Config::get('ntrust.profiles.' . self::$roleProfile . '.role_user_table'))->flush();
}
}
public function restore()
{ //soft delete undo's
parent::restore();
if(Cache::getStore() instanceof TaggableStore) {
Cache::tags(Config::get('ntrust.profiles.' . self::$roleProfile . '.role_user_table'))->flush();
}
}
//omitted
} There's a public method This is how I do in an registerd observer: <?php
namespace App\Observers;
use App\User;
class UserObserver
{
//omitted
public function deleting(User $user)
{
if($user->isForceDeleting()) {
//hard deleting
info('hard');
}
else {
//soft deleting
info('soft');
}
}
} Another approach is to use |
I found issue. I will update you code or give you solution soon. |
Got solution. Use below code and it will well. Let me know if it will generate other issue. Replace: // use SoftDeletes;
// use NtrustRoleTrait; With: use SoftDeletes, NtrustRoleTrait
{
SoftDeletes::restore insteadof NtrustRoleTrait;
NtrustRoleTrait::restore insteadof SoftDeletes;
} |
Thanks for your solution but I think you are erasing I did a test: <?php
trait A
{
function restore()
{
echo "A";
}
}
trait B
{
function restore()
{
echo "B";
}
}
class Model {
function restore()
{
echo "Model";
}
}
class User extends Model {
use A, B {
A::restore insteadof B;
B::restore insteadof A;
}
}
$user = new User;
$user->restore(); //result is 'Model' |
This one will work: <?php
trait A
{
function restore()
{
parent::restore();
echo "A";
}
}
trait B
{
function restore()
{
parent::restore();
echo "B";
}
}
class Model {
function restore()
{
echo "Model";
}
}
class BaseUser extends Model {
use A;
}
class User extends BaseUser {
use B;
}
$user = new User;
$user->restore(); //result is 'ModelAB' |
But there is one problem class Model don't have |
Hmm sorry I forget that. In our condition it should be <?php
trait A
{
function restore()
{
echo "A";
}
}
trait B
{
function restore()
{
echo "B";
}
}
class Model {
}
class User extends Model {
use A, B {
A::restore as restoreA;
B::restore as restoreB;
}
function restore(){
$this->restoreA();
$this->restoreB();
}
}
$user = new User;
$user->restore(); //result is 'AB' |
Great. That one will work perfectly. Thanks for solution. I did not test on my solution. I will update document. Let me know if you will find any other solution directly on trait then I will apply on that on. I might use restore event |
There is one more thing. Why is there a |
I have actually copied this package from other and fix many laravel 5.0 to 5.3 bugs. So no idea why they calling parent::restore() event parent don't have restore method. And I did no focus for testing soft delete so missed that area. I will update this package in day or two with event thing. It will fix all this issue. Or you can fork package and make pull request and I will merge it. |
Pull request created. Closed. |
Hey @theoxuan Thanks for pull request. I have merge that one and applied other setting for all traits also now you can use normal. use SoftDeletes;
use NtrustUserTrait; Can you please try with Thanks for fix and help to build great package. |
Sorry dude I forgot to give you my feedback. This package is just not Laravel-5.3 ready. A lot of internal function calls are broken. In the end I implemented my own permission controlling system. Thanks anyway! |
Hi @seancheung Thanks for feedback. It would be great if you can give me one or two example like what thing is not working. I am using in my live project this roles and permission things and working great for me but if it has any bug then I can fix it. |
@ajmerainfo It's inspired by your package(and the original package you forked). |
Great. Thank you for information. |
Dude I just found a method named I think it's better to stop overriding Here is how it's handled in /**
* The "booting" method of the model.
*
* @return void
*/
protected static function boot()
{
static::bootTraits();
}
/**
* Boot all of the bootable traits on the model.
*
* @return void
*/
protected static function bootTraits()
{
$class = static::class;
foreach (class_uses_recursive($class) as $trait) {
if (method_exists($class, $method = 'boot'.class_basename($trait))) {
forward_static_call([$class, $method]);
}
}
} Also do not override model events but listen to them. Register listening in This will completely remove those collisions with ease. |
Good to know. Thank you for great information. I will implement that one in this package. About model event I am using like below is that perfect? static::saved(function()
{
if(Cache::getStore() instanceof TaggableStore) {
Cache::tags(Config::get('ntrust.profiles.' . self::$roleProfile . '.role_user_table'))
->flush();
}
});
static::deleted(function($user)
{
if(Cache::getStore() instanceof TaggableStore) {
Cache::tags(Config::get('ntrust.profiles.' . self::$roleProfile . '.role_user_table'))
->flush();
$user->roles()->sync([]);
}
});
if(method_exists(self::class, 'restored')) {
static::restored(function($user)
{
if(Cache::getStore() instanceof TaggableStore) {
Cache::tags(Config::get('ntrust.profiles.' . self::$roleProfile . '.role_user_table'))
->flush();
$user->roles()->sync([]);
}
});
} |
It is alright. But I think a separate observer would be cleaner: <?php
namespace Your\Package;
class YourModelObserver
{
/**
* Listen to the Model saved event.
*
* @param mixed $model
* @return void
*/
public function saved($model)
{
//
}
/**
* Listen to the Model deleting event.
*
* @param mixed $model
* @return void
*/
public function deleting($model)
{
if($model->forceDelete()) {
//softdelete
}
else {
//hard delete
}
//
}
/**
* Listen to the Model restored event.
*
* @param mixed $model
* @return void
*/
public function restored($model)
{
//
}
} Just register it to the model like this <?php
namespace Your\Package;
trait YourModelTrait
{
public static function bootYourModelTrait()
{
static::observe(YourModelObserver::class);
}
} With this you don't event need to check method existence(like Another suggestion is to pick I think there are some problems(or my misunderstanding?) with the logic in your code.
|
I have this model:
And I noticed that there is a collision between
NtrustUserTrait
andSoftDeletes
: therestore
method, which both traits has overridden fromModel
.Am I doing wrong or is this a bug?
The text was updated successfully, but these errors were encountered: