mikebronner / laravel-model-caching

Eloquent model-caching made easy.
MIT License
2.26k stars 217 forks source link

relation_name.updated_at - wrong timestamp updating #290

Closed emprove closed 5 years ago

emprove commented 5 years ago

When updating some cached model with jenssegers/mongodb package, Eloquent builder add "collection_name.updated_at" values and not updating original updated_at field. I think my code use this part of the Cachable trait:

use PivotEventTrait {
        ModelCaching::newBelongsToMany insteadof PivotEventTrait;
    }

Eloquent Query

array:2 [
  0 => array:3 [
    "query" => "estate_subjects.find({"$or":[{"alias":"tpu15"},{"alias":{"$regex":"^tpu15\\-.*","$options":"i"}}]},{"projection":{"alias":true,"_id":true},"typeMap":{"root":"array","document":"array"}})"
    "bindings" => []
    "time" => 0.46
  ]
  1 => array:3 [
    "query" => "estate_subjects.UpdateMany({"_id":"5d79f2b9c34ca9000e2e7d04"},{"$set":{"name":"tpu15","alias":"tpu15","estate_subjects.updated_at":{"$date":{"$numberLong":"1568293131000"}}}},{"multiple":true})"
    "bindings" => []
    "time" => 2.39
  ]
]

class EstateSubject extends MongoDBList
{
    use Cachable;

    /**
     * @return HasMany
     */
    public function projects()
    {
        return $this->hasMany(Project::class);
    }
}

Environment

mikebronner commented 5 years ago

Hi @emprove, thanks for writing in. Can you provide the actual eloquent query code (not a dump) that you are running, where you expect the updated_at to be updated? Also, can you provide the code for the models involved on both sides of the relationship, as well as the class definition for MongoDBList? My first thought is that you are trying to use this with jenssegers MongoDB implementation, which might not be 100% eloquent-compatible under the hood.

emprove commented 5 years ago
$listItem->update(['name' => $request->name]);

MongoDBList:

namespace App\Models\Base;

use Cviebrock\EloquentSluggable\Sluggable;
use Jenssegers\Mongodb\Eloquent\Builder;

/**
 * @property string $name  Название
 * @property string $alias Символьное имя
 *
 * @mixin Builder
 */
class MongoDBList extends MongoDBModel
{
    use Sluggable;

    protected $fillable = [
        'name',
    ];

    protected $rules = [
        'name' => 'required|string',
    ];

    public function sluggable(): array
    {
        return [
            'alias' => [
                'source' => 'name',
            ],
        ];
    }
}

MongoDBModel

namespace App\Models\Base;

use App\Models\User;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Support\Carbon;
use Jenssegers\Mongodb\Eloquent\Builder;
use Jenssegers\Mongodb\Eloquent\Model;
use Watson\Validating\ValidatingTrait;
use Wildside\Userstamps\Userstamps;

/**
 * @property string $id
 * @property int    $created_by ID пользователя кем создано (MySQL entity)
 * @property int    $updated_by ID пользователя кем обновлено (MySQL entity)
 * @property Carbon $created_at Время создания
 * @property Carbon $updated_at Время обновления
 *
 * @property User   $creator    Пользователь кем создано (MySQL entity)
 * @property User   $editor     Пользователь кем обновлено (MySQL entity)
 *
 * @mixin Builder
 */
class MongoDBModel extends Model
{
    use Userstamps, ValidatingTrait;

    protected $connection = 'mongodb';

    protected $rules = [];

    /**
     * Whether the model should throw a ValidationException if it
     * fails validation. If not set, it will default to false.
     * Needs to override for using own message responses.
     *
     * @var boolean
     */
    protected $throwValidationExceptions = true;

    /**
     * You can use mongo <-> mysql relations as normal way (but limited)
     *
     * @return BelongsTo
     */
    public function creator()
    {
        return $this->belongsTo(User::class, 'created_by');
    }

    /**
     * @return BelongsTo
     */
    public function editor()
    {
        return $this->belongsTo(User::class, 'updated_by');
    }
}
mikebronner commented 5 years ago

@emprove Yea, this won't work with model-caching, as it is implementing a custom builder class. I'm afraid at this time the MongoDB package is incompatible.

emprove commented 5 years ago

@mikebronner if you have some time read this please: Related topics: laravel/framework#26995 laravel/framework#26997 laravel/framework#27791

Maybe this can help.

mikebronner commented 5 years ago

The problem appears to be that your models are not using the CachedBuilder class for certain operations, especially relationships, under the hood. Can you provide a repo that reproduces the issue for me?

In general I am unable to support implementations of packages that do not use Laravel's EloquentBuilder under the hood. I am happy to provide custom programming in exchange for support on Patreon.

If you provide a simple repo that reproduces the issue, I will take a look to see if I can isolate the issue. Also, if you are able to recreate the issue using Laravel Eloquent (and not MongoDB), I will be happy to look into it.

Sorry, there is only so much free support I can provide in an open-source package like this. I hope you understand.

I do appreciate you writing in, and of course using the package in the first place. Thank you for that! :)