mikebronner / laravel-model-caching

Eloquent model-caching made easy.
MIT License
2.25k stars 212 forks source link

Scopes being applied twice #289

Closed mycarrysun closed 4 years ago

mycarrysun commented 5 years ago

Describe the bug When applying scopes, if there is a join it is applied twice.

Eloquent Query Please provide the complete eloquent query that caused the bug, for example:

// Order is a model with trait Cachable;
Order::with(Order::$RELATIONS[$relations])
                      ->selectAll() // this is a scope that just selects all columns, it is not applied twice
                      ->withCompany() //the join here is applied twice
                      ->withGlobalScope('with_created_user', new ScopeWithCreatedUser) // the join here is also applied twice
                      ->simplePaginate();

Stack Trace The stacktrace below was generated with a dd() inside Illuminate\Database\Query\Builder::join() only on the second time the function is fired for the same table. I confirmed that the scope is not being applied twice in the scope's handler using the same method. It is also in reverse order so the last line is the most recent function call.

24 => array:7 [
    "file" => "/home/myproject/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php"
    "line" => 163
    "function" => "handle"
    "class" => "App\Http\Middleware\FrameOptions"
    "object" => App\Http\Middleware\FrameOptions^ {#1202}
    "type" => "->"
    "args" => array:2 [
      0 => Dingo\Api\Http\Request^ {#1173}
      1 => Closure($passable)^ {#1176}
    ]
  ]
  25 => array:7 [
    "file" => "/home/myproject/app/Http/Middleware/FrameOptions.php"
    "line" => 19
    "function" => "Illuminate\Pipeline\{closure}"
    "class" => "Illuminate\Pipeline\Pipeline"
    "object" => Illuminate\Pipeline\Pipeline^ {#1182}
    "type" => "->"
    "args" => array:1 [
      0 => Dingo\Api\Http\Request^ {#1173}
    ]
  ]
  26 => array:7 [
    "file" => "/home/myproject/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php"
    "line" => 163
    "function" => "handle"
    "class" => "App\Http\Middleware\Timezone"
    "object" => App\Http\Middleware\Timezone^ {#1197}
    "type" => "->"
    "args" => array:2 [
      0 => Dingo\Api\Http\Request^ {#1173}
      1 => Closure($passable)^ {#1180}
    ]
  ]
  27 => array:7 [
    "file" => "/home/myproject/app/Http/Middleware/Timezone.php"
    "line" => 29
    "function" => "Illuminate\Pipeline\{closure}"
    "class" => "Illuminate\Pipeline\Pipeline"
    "object" => Illuminate\Pipeline\Pipeline^ {#1182}
    "type" => "->"
    "args" => array:1 [
      0 => Dingo\Api\Http\Request^ {#1173}
    ]
  ]
  28 => array:7 [
    "file" => "/home/myproject/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php"
    "line" => 128
    "function" => "Dingo\Api\Http\Middleware\{closure}"
    "class" => "Dingo\Api\Http\Middleware\Request"
    "object" => Dingo\Api\Http\Middleware\Request^ {#198}
    "type" => "->"
    "args" => array:1 [
      0 => Dingo\Api\Http\Request^ {#1173}
    ]
  ]
  29 => array:7 [
    "file" => "/home/myproject/vendor/dingo/api/src/Http/Middleware/Request.php"
    "line" => 126
    "function" => "dispatch"
    "class" => "Dingo\Api\Routing\Router"
    "object" => Dingo\Api\Routing\Router^ {#202}
    "type" => "->"
    "args" => array:1 [
      0 => Dingo\Api\Http\Request^ {#1173}
    ]
  ]
  30 => array:7 [
    "file" => "/home/myproject/vendor/dingo/api/src/Routing/Router.php"
    "line" => 514
    "function" => "dispatch"
    "class" => "Dingo\Api\Routing\Adapter\Laravel"
    "object" => Dingo\Api\Routing\Adapter\Laravel^ {#195}
    "type" => "->"
    "args" => array:2 [
      0 => Dingo\Api\Http\Request^ {#1173}
      1 => "v1"
    ]
  ]
  31 => array:7 [
    "file" => "/home/myproject/vendor/dingo/api/src/Routing/Adapter/Laravel.php"
    "line" => 88
    "function" => "dispatch"
    "class" => "Illuminate\Routing\Router"
    "object" => Illuminate\Routing\Router^ {#1199}
    "type" => "->"
    "args" => array:1 [
      0 => Dingo\Api\Http\Request^ {#1173}
    ]
  ]
  32 => array:7 [
    "file" => "/home/myproject/vendor/laravel/framework/src/Illuminate/Routing/Router.php"
    "line" => 612
    "function" => "dispatchToRoute"
    "class" => "Illuminate\Routing\Router"
    "object" => Illuminate\Routing\Router^ {#1199}
    "type" => "->"
    "args" => array:1 [
      0 => Dingo\Api\Http\Request^ {#1173}
    ]
  ]
  33 => array:7 [
    "file" => "/home/myproject/vendor/laravel/framework/src/Illuminate/Routing/Router.php"
    "line" => 623
    "function" => "runRoute"
    "class" => "Illuminate\Routing\Router"
    "object" => Illuminate\Routing\Router^ {#1199}
    "type" => "->"
    "args" => array:2 [
      0 => Dingo\Api\Http\Request^ {#1173}
      1 => Illuminate\Routing\Route^ {#937}
    ]
  ]
  34 => array:7 [
    "file" => "/home/myproject/vendor/laravel/framework/src/Illuminate/Routing/Router.php"
    "line" => 657
    "function" => "runRouteWithinStack"
    "class" => "Illuminate\Routing\Router"
    "object" => Illuminate\Routing\Router^ {#1199}
    "type" => "->"
    "args" => array:2 [
      0 => Illuminate\Routing\Route^ {#937}
      1 => Dingo\Api\Http\Request^ {#1173}
    ]
  ]
  35 => array:7 [
    "file" => "/home/myproject/vendor/laravel/framework/src/Illuminate/Routing/Router.php"
    "line" => 682
    "function" => "then"
    "class" => "Illuminate\Pipeline\Pipeline"
    "object" => Illuminate\Routing\Pipeline^ {#1206
      #container: Illuminate\Foundation\Application^ {#4}
      #passable: Dingo\Api\Http\Request^ {#1173}
      #pipes: array:5 [
        0 => "Dingo\Api\Http\Middleware\PrepareController"
        1 => "Tymon\JWTAuth\Http\Middleware\Authenticate"
        2 => "App\Http\Middleware\SentryContext"
        3 => "App\Http\Middleware\UserIsActive"
        4 => "Illuminate\Routing\Middleware\SubstituteBindings"
      ]
      #method: "handle"
    }
    "type" => "->"
    "args" => array:1 [
      0 => Closure($request)^ {#1203
        class: "Illuminate\Routing\Router"
        this: Illuminate\Routing\Router^ {#1199}
        use: { …1}
        file: "./vendor/laravel/framework/src/Illuminate/Routing/Router.php"
        line: "678 to 682"
      }
    ]
  ]
  36 => array:7 [
    "file" => "/home/myproject/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php"
    "line" => 104
    "function" => "Illuminate\Routing\{closure}"
    "class" => "Illuminate\Routing\Pipeline"
    "object" => Illuminate\Routing\Pipeline^ {#1206}
    "type" => "->"
    "args" => array:1 [
      0 => Dingo\Api\Http\Request^ {#1173}
    ]
  ]
  37 => array:7 [
    "file" => "/home/myproject/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php"
    "line" => 53
    "function" => "Illuminate\Pipeline\{closure}"
    "class" => "Illuminate\Pipeline\Pipeline"
    "object" => Illuminate\Routing\Pipeline^ {#1206}
    "type" => "->"
    "args" => array:1 [
      0 => Dingo\Api\Http\Request^ {#1173}
    ]
  ]
  38 => array:7 [
    "file" => "/home/myproject/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php"
    "line" => 163
    "function" => "handle"
    "class" => "Dingo\Api\Http\Middleware\PrepareController"
    "object" => Dingo\Api\Http\Middleware\PrepareController^ {#1281}
    "type" => "->"
    "args" => array:2 [
      0 => Dingo\Api\Http\Request^ {#1173}
      1 => Closure($passable)^ {#1278
        class: "Illuminate\Routing\Pipeline"
        this: Illuminate\Routing\Pipeline^ {#1206}
        use: { …2}
        file: "./vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php"
        line: "47 to 59"
      }
    ]
  ]
  39 => array:7 [
    "file" => "/home/myproject/vendor/dingo/api/src/Http/Middleware/PrepareController.php"
    "line" => 45
    "function" => "Illuminate\Routing\{closure}"
    "class" => "Illuminate\Routing\Pipeline"
    "object" => Illuminate\Routing\Pipeline^ {#1206}
    "type" => "->"
    "args" => array:1 [
      0 => Dingo\Api\Http\Request^ {#1173}
    ]
  ]
  40 => array:7 [
    "file" => "/home/myproject/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php"
    "line" => 53
    "function" => "Illuminate\Pipeline\{closure}"
    "class" => "Illuminate\Pipeline\Pipeline"
    "object" => Illuminate\Routing\Pipeline^ {#1206}
    "type" => "->"
    "args" => array:1 [
      0 => Dingo\Api\Http\Request^ {#1173}
    ]
  ]
  41 => array:7 [
    "file" => "/home/myproject/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php"
    "line" => 163
    "function" => "handle"
    "class" => "Tymon\JWTAuth\Http\Middleware\Authenticate"
    "object" => Tymon\JWTAuth\Http\Middleware\Authenticate^ {#1336
      #auth: Tymon\JWTAuth\JWTAuth^ {#1289}
    }
    "type" => "->"
    "args" => array:2 [
      0 => Dingo\Api\Http\Request^ {#1173}
      1 => Closure($passable)^ {#1277
        class: "Illuminate\Routing\Pipeline"
        this: Illuminate\Routing\Pipeline^ {#1206}
        use: { …2}
        file: "./vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php"
        line: "47 to 59"
      }
    ]
  ]
  42 => array:7 [
    "file" => "/home/myproject/vendor/tymon/jwt-auth/src/Http/Middleware/Authenticate.php"
    "line" => 32
    "function" => "Illuminate\Routing\{closure}"
    "class" => "Illuminate\Routing\Pipeline"
    "object" => Illuminate\Routing\Pipeline^ {#1206}
    "type" => "->"
    "args" => array:1 [
      0 => Dingo\Api\Http\Request^ {#1173}
    ]
  ]
  43 => array:7 [
    "file" => "/home/myproject/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php"
    "line" => 53
    "function" => "Illuminate\Pipeline\{closure}"
    "class" => "Illuminate\Pipeline\Pipeline"
    "object" => Illuminate\Routing\Pipeline^ {#1206}
    "type" => "->"
    "args" => array:1 [
      0 => Dingo\Api\Http\Request^ {#1173}
    ]
  ]
  44 => array:7 [
    "file" => "/home/myproject/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php"
    "line" => 163
    "function" => "handle"
    "class" => "App\Http\Middleware\SentryContext"
    "object" => App\Http\Middleware\SentryContext^ {#1342}
    "type" => "->"
    "args" => array:2 [
      0 => Dingo\Api\Http\Request^ {#1173}
      1 => Closure($passable)^ {#1276
        class: "Illuminate\Routing\Pipeline"
        this: Illuminate\Routing\Pipeline^ {#1206}
        use: { …2}
        file: "./vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php"
        line: "47 to 59"
      }
    ]
  ]
  45 => array:7 [
    "file" => "/home/myproject/app/Http/Middleware/SentryContext.php"
    "line" => 38
    "function" => "Illuminate\Routing\{closure}"
    "class" => "Illuminate\Routing\Pipeline"
    "object" => Illuminate\Routing\Pipeline^ {#1206}
    "type" => "->"
    "args" => array:1 [
      0 => Dingo\Api\Http\Request^ {#1173}
    ]
  ]
  46 => array:7 [
    "file" => "/home/myproject/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php"
    "line" => 53
    "function" => "Illuminate\Pipeline\{closure}"
    "class" => "Illuminate\Pipeline\Pipeline"
    "object" => Illuminate\Routing\Pipeline^ {#1206}
    "type" => "->"
    "args" => array:1 [
      0 => Dingo\Api\Http\Request^ {#1173}
    ]
  ]
  47 => array:7 [
    "file" => "/home/myproject/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php"
    "line" => 163
    "function" => "handle"
    "class" => "App\Http\Middleware\UserIsActive"
    "object" => App\Http\Middleware\UserIsActive^ {#1337}
    "type" => "->"
    "args" => array:2 [
      0 => Dingo\Api\Http\Request^ {#1173}
      1 => Closure($passable)^ {#1275
        class: "Illuminate\Routing\Pipeline"
        this: Illuminate\Routing\Pipeline^ {#1206}
        use: { …2}
        file: "./vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php"
        line: "47 to 59"
      }
    ]
  ]
  48 => array:7 [
    "file" => "/home/myproject/app/Http/Middleware/UserIsActive.php"
    "line" => 49
    "function" => "Illuminate\Routing\{closure}"
    "class" => "Illuminate\Routing\Pipeline"
    "object" => Illuminate\Routing\Pipeline^ {#1206}
    "type" => "->"
    "args" => array:1 [
      0 => Dingo\Api\Http\Request^ {#1173}
    ]
  ]
  49 => array:7 [
    "file" => "/home/myproject/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php"
    "line" => 53
    "function" => "Illuminate\Pipeline\{closure}"
    "class" => "Illuminate\Pipeline\Pipeline"
    "object" => Illuminate\Routing\Pipeline^ {#1206}
    "type" => "->"
    "args" => array:1 [
      0 => Dingo\Api\Http\Request^ {#1173}
    ]
  ]
  50 => array:7 [
    "file" => "/home/myproject/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php"
    "line" => 163
    "function" => "handle"
    "class" => "Illuminate\Routing\Middleware\SubstituteBindings"
    "object" => Illuminate\Routing\Middleware\SubstituteBindings^ {#1348
      #router: Illuminate\Routing\Router^ {#27}
    }
    "type" => "->"
    "args" => array:2 [
      0 => Dingo\Api\Http\Request^ {#1173}
      1 => Closure($passable)^ {#1212
        class: "Illuminate\Routing\Pipeline"
        this: Illuminate\Routing\Pipeline^ {#1206}
        use: { …1}
        file: "./vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php"
        line: "28 to 36"
      }
    ]
  ]
  51 => array:7 [
    "file" => "/home/myproject/vendor/laravel/framework/src/Illuminate/Routing/Middleware/SubstituteBindings.php"
    "line" => 41
    "function" => "Illuminate\Routing\{closure}"
    "class" => "Illuminate\Routing\Pipeline"
    "object" => Illuminate\Routing\Pipeline^ {#1206}
    "type" => "->"
    "args" => array:1 [
      0 => Dingo\Api\Http\Request^ {#1173}
    ]
  ]
  52 => array:7 [
    "file" => "/home/myproject/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php"
    "line" => 30
    "function" => "Illuminate\Routing\{closure}"
    "class" => "Illuminate\Routing\Router"
    "object" => Illuminate\Routing\Router^ {#1199}
    "type" => "->"
    "args" => array:1 [
      0 => Dingo\Api\Http\Request^ {#1173}
    ]
  ]
  53 => array:7 [
    "file" => "/home/myproject/vendor/laravel/framework/src/Illuminate/Routing/Router.php"
    "line" => 680
    "function" => "run"
    "class" => "Illuminate\Routing\Route"
    "object" => Illuminate\Routing\Route^ {#937}
    "type" => "->"
    "args" => []
  ]
  54 => array:7 [
    "file" => "/home/myproject/vendor/laravel/framework/src/Illuminate/Routing/Route.php"
    "line" => 176
    "function" => "runController"
    "class" => "Illuminate\Routing\Route"
    "object" => Illuminate\Routing\Route^ {#937}
    "type" => "->"
    "args" => []
  ]
  55 => array:7 [
    "file" => "/home/myproject/vendor/laravel/framework/src/Illuminate/Routing/Route.php"
    "line" => 219
    "function" => "dispatch"
    "class" => "Illuminate\Routing\ControllerDispatcher"
    "object" => Illuminate\Routing\ControllerDispatcher^ {#22}
    "type" => "->"
    "args" => array:3 [
      0 => Illuminate\Routing\Route^ {#937}
      1 => App\Api\Controllers\OrderController^ {#1207}
      2 => "index"
    ]
  ]
  56 => array:7 [
    "file" => "/home/myproject/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php"
    "line" => 45
    "function" => "callAction"
    "class" => "Illuminate\Routing\Controller"
    "object" => App\Api\Controllers\OrderController^ {#1207}
    "type" => "->"
    "args" => array:2 [
      0 => "index"
      1 => array:1 [
        0 => Dingo\Api\Http\Request^ {#1173}
      ]
    ]
  ]
  57 => array:4 [
    "file" => "/home/myproject/vendor/laravel/framework/src/Illuminate/Routing/Controller.php"
    "line" => 54
    "function" => "call_user_func_array"
    "args" => array:2 [
      0 => array:2 [
        0 => App\Api\Controllers\OrderController^ {#1207}
        1 => "index"
      ]
      1 => array:1 [
        0 => Dingo\Api\Http\Request^ {#1173}
      ]
    ]
  ]
  58 => array:5 [
    "function" => "index"
    "class" => "App\Api\Controllers\OrderController"
    "object" => App\Api\Controllers\OrderController^ {#1207}
    "type" => "->"
    "args" => array:1 [
      0 => Dingo\Api\Http\Request^ {#1173}
    ]
  ]
  59 => array:7 [
    "file" => "/home/myproject/app/Api/Controllers/OrderController.php"
    "line" => 111
    "function" => "simplePaginate"
    "class" => "Illuminate\Database\Eloquent\Builder"
    "object" => GeneaLabs\LaravelModelCaching\CachedBuilder^ {#1361
      #query: Illuminate\Database\Query\Builder^ {#1360
        +connection: Illuminate\Database\MySqlConnection^ {#278
          #pdo: Doctrine\DBAL\Driver\PDOConnection^ {#1357 …2}
          #readPdo: null
          #database: "ac09n332_dev"
          #tablePrefix: ""
          #config: array:13 [ …13]
          #reconnector: Closure($connection)^ {#39 …4}
          #queryGrammar: Illuminate\Database\Query\Grammars\MySqlGrammar^ {#279
            #operators: array:1 [ …1]
            #selectComponents: array:11 [ …11]
            #tablePrefix: ""
          }
          #schemaGrammar: Illuminate\Database\Schema\Grammars\MySqlGrammar^ {#272 …5}
          #postProcessor: Illuminate\Database\Query\Processors\MySqlProcessor^ {#280}
          #events: Illuminate\Events\Dispatcher^ {#28}
          #fetchMode: 5
          #transactions: 0
          #recordsModified: true
          #queryLog: array:2 [ …2]
          #loggingQueries: true
          #pretending: false
          #doctrineConnection: null
        }
        +grammar: Illuminate\Database\Query\Grammars\MySqlGrammar^ {#279}
        +processor: Illuminate\Database\Query\Processors\MySqlProcessor^ {#280}
        +bindings: array:7 [ …7]
        +aggregate: null
        +columns: array:7 [ …7]
        +distinct: false
        +from: "orders"
        +joins: array:2 [ …2]
        +wheres: array:3 [ …3]
        +groups: array:1 [ …1]
        +havings: null
        +orders: array:2 [ …2]
        +limit: 11
        +offset: 40
        +unions: null
        +unionLimit: null
        +unionOffset: null
        +unionOrders: null
        +lock: null
        +operators: array:30 [ …30]
        +useWritePdo: false
      }
      #model: App\Order^ {#1367
        #table: "orders"
        #fillable: array:13 [ …13]
        #dates: array:5 [ …5]
        #appends: array:1 [ …1]
        #hidden: array:1 [ …1]
        #casts: array:2 [ …2]
        #connection: null
        #primaryKey: "id"
        #keyType: "int"
        +incrementing: true
        #with: []
        #withCount: []
        #perPage: 15
        +exists: false
        +wasRecentlyCreated: false
        #attributes: []
        #original: []
        #changes: []
        #dateFormat: null
        #dispatchesEvents: []
        #observables: []
        #relations: []
        #touches: []
        +timestamps: true
        #visible: []
        #guarded: array:1 [ …1]
        #isCachable: true
        #scopesAreApplied: false
        #macroKey: ""
        #forceDeleting: false
      }
      #eagerLoad: []
      #localMacros: array:4 [
        "restore" => Closure(Builder $builder)^ {#1366 …4}
        "withTrashed" => Closure(Builder $builder, $withTrashed = true)^ {#1365 …4}
        "withoutTrashed" => Closure(Builder $builder)^ {#1362 …4}
        "onlyTrashed" => Closure(Builder $builder)^ {#1346 …4}
      ]
      #onDelete: Closure(Builder $builder)^ {#271
        class: "Illuminate\Database\Eloquent\SoftDeletingScope"
        this: Illuminate\Database\Eloquent\SoftDeletingScope {#411}
        file: "./vendor/laravel/framework/src/Illuminate/Database/Eloquent/SoftDeletingScope.php"
        line: "38 to 44"
      }
      #passthru: array:17 [
        0 => "insert"
        1 => "insertOrIgnore"
        2 => "insertGetId"
        3 => "insertUsing"
        4 => "getBindings"
        5 => "toSql"
        6 => "dump"
        7 => "dd"
        8 => "exists"
        9 => "doesntExist"
        10 => "count"
        11 => "min"
        12 => "max"
        13 => "avg"
        14 => "average"
        15 => "sum"
        16 => "getConnection"
      ]
      #scopes: array:7 [
        "Illuminate\Database\Eloquent\SoftDeletingScope" => Illuminate\Database\Eloquent\SoftDeletingScope {#411}
        "Scopes\RecentScope" => Scopes\RecentScope^ {#412}
        "Scopes\RestrictByCompany" => Scopes\RestrictByCompany^ {#413}
        "with_created_user" => Scopes\ScopeWithCreatedUser^ {#1358}
        "with_contact" => Scopes\ScopeWithContact^ {#1368}
        "restrict_drafts_and_cart" => Scopes\RestrictDraftsAndCart^ {#1378}
        "comment_count" => Scopes\ScopeWithCommentCount^ {#1371}
      ]
      #removedScopes: []
      #isCachable: true
      #scopesAreApplied: true
      #macroKey: ""
    }
    "type" => "->"
    "args" => array:4 [
      0 => "10"
      1 => array:1 [
        0 => "*"
      ]
      2 => "page"
      3 => "5"
    ]
  ]
  60 => array:7 [
    "file" => "/home/myproject/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php"
    "line" => 780
    "function" => "get"
    "class" => "GeneaLabs\LaravelModelCaching\CachedBuilder"
    "object" => GeneaLabs\LaravelModelCaching\CachedBuilder^ {#1361}
    "type" => "->"
    "args" => array:1 [
      0 => array:1 [
        0 => "*"
      ]
    ]
  ]
  61 => array:7 [
    "file" => "/home/myproject/vendor/genealabs/laravel-model-caching/src/Traits/Buildable.php"
    "line" => 97
    "function" => "cachedValue"
    "class" => "GeneaLabs\LaravelModelCaching\CachedBuilder"
    "object" => GeneaLabs\LaravelModelCaching\CachedBuilder^ {#1361}
    "type" => "->"
    "args" => array:2 [
      0 => array:1 [
        0 => array:1 [ …1]
      ]
      1 => "genealabs:laravel-model-caching:mysql:ac09n332_dev:orders:apporder_orders.*_(select companies.name as company_name from `companies` where `companies`.`id` = orders.company_id) as `company_name`_(select count(distinct permits.carrier_id) from `permits` where `permits`.`order_id` = orders.id and `permits`.`deleted_at` is null) as `carrier_count`_concat(coalesce(cu.first_name, ""), " ", coalesce(cu.last_name, "")) as created_by_name_(select CONCAT(COALESCE(users.first_name, ""), " ", COALESCE(users.last_name, "")) as contact_name from `users` where `users`.`id` = orders.contact_id) as `contact_name`_count(distinct comments.id) as comment_count_(select count(distinct comments.id) as important where comments.important = 1 limit 1) as important-orders.deleted_at_null-orders.company_id_=_88-nested-nested-orders.status_id_in_draft_in_cart_staff_cart-(select users.account_type_id from users where users.id = orders.created_by)_in_customer_customer_admin-orders.status_id_notin_draft_in_cart_staff_cart_orderBy_created_at_desc_orderBy_orders.id_desc-offset_40-limit_11"
    ]
  ]
  62 => array:7 [
    "file" => "/home/myproject/vendor/genealabs/laravel-model-caching/src/Traits/Buildable.php"
    "line" => 231
    "function" => "retrieveCachedValue"
    "class" => "GeneaLabs\LaravelModelCaching\CachedBuilder"
    "object" => GeneaLabs\LaravelModelCaching\CachedBuilder^ {#1361}
    "type" => "->"
    "args" => array:5 [
      0 => array:1 [
        0 => array:1 [ …1]
      ]
      1 => "genealabs:laravel-model-caching:mysql:ac09n332_dev:orders:apporder_orders.*_(select companies.name as company_name from `companies` where `companies`.`id` = orders.company_id) as `company_name`_(select count(distinct permits.carrier_id) from `permits` where `permits`.`order_id` = orders.id and `permits`.`deleted_at` is null) as `carrier_count`_concat(coalesce(cu.first_name, ""), " ", coalesce(cu.last_name, "")) as created_by_name_(select CONCAT(COALESCE(users.first_name, ""), " ", COALESCE(users.last_name, "")) as contact_name from `users` where `users`.`id` = orders.contact_id) as `contact_name`_count(distinct comments.id) as comment_count_(select count(distinct comments.id) as important where comments.important = 1 limit 1) as important-orders.deleted_at_null-orders.company_id_=_88-nested-nested-orders.status_id_in_draft_in_cart_staff_cart-(select users.account_type_id from users where users.id = orders.created_by)_in_customer_customer_admin-orders.status_id_notin_draft_in_cart_staff_cart_orderBy_created_at_desc_orderBy_orders.id_desc-offset_40-limit_11"
      2 => array:1 [
        0 => "genealabs:laravel-model-caching:mysql:ac09n332_dev:apporder"
      ]
      3 => "156b3d1b45e0bd52136f854e979128d4aaa4ce66"
      4 => "get"
    ]
  ]
  63 => array:7 [
    "file" => "/home/myproject/vendor/genealabs/laravel-model-caching/src/Traits/Buildable.php"
    "line" => 292
    "function" => "rememberForever"
    "class" => "Illuminate\Cache\Repository"
    "object" => Illuminate\Cache\RedisTaggedCache^ {#1374
      #tags: Illuminate\Cache\TagSet^ {#1390
        #store: Illuminate\Cache\RedisStore^ {#1312
          #redis: Illuminate\Redis\RedisManager^ {#1311 …6}
          #prefix: "laravel:"
          #connection: "default"
        }
        #names: array:1 [ …1]
      }
      #store: Illuminate\Cache\RedisStore^ {#1312}
      #events: Illuminate\Events\Dispatcher^ {#28}
      #default: 3600
    }
    "type" => "->"
    "args" => array:2 [
      0 => "156b3d1b45e0bd52136f854e979128d4aaa4ce66"
      1 => Closure()^ {#1392
        class: "GeneaLabs\LaravelModelCaching\CachedBuilder"
        this: GeneaLabs\LaravelModelCaching\CachedBuilder^ {#1361}
        use: { …3}
        file: "./vendor/genealabs/laravel-model-caching/src/Traits/Buildable.php"
        line: "287 to 292"
      }
    ]
  ]
  64 => array:7 [
    "file" => "/home/myproject/vendor/laravel/framework/src/Illuminate/Cache/Repository.php"
    "line" => 418
    "function" => "GeneaLabs\LaravelModelCaching\Traits\{closure}"
    "class" => "GeneaLabs\LaravelModelCaching\CachedBuilder"
    "object" => GeneaLabs\LaravelModelCaching\CachedBuilder^ {#1361}
    "type" => "->"
    "args" => []
  ]
  65 => array:7 [
    "file" => "/home/myproject/vendor/genealabs/laravel-model-caching/src/Traits/Buildable.php"
    "line" => 290
    "function" => "get"
    "class" => "Illuminate\Database\Eloquent\Builder"
    "object" => GeneaLabs\LaravelModelCaching\CachedBuilder^ {#1361}
    "type" => "->"
    "args" => array:1 [
      0 => array:1 [
        0 => "*"
      ]
    ]
  ]
  66 => array:7 [
    "file" => "/home/myproject/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php"
    "line" => 500
    "function" => "applyScopes"
    "class" => "Illuminate\Database\Eloquent\Builder"
    "object" => GeneaLabs\LaravelModelCaching\CachedBuilder^ {#1361}
    "type" => "->"
    "args" => []
  ]
  67 => array:7 [
    "file" => "/home/myproject/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php"
    "line" => 983
    "function" => "callScope"
    "class" => "Illuminate\Database\Eloquent\Builder"
    "object" => GeneaLabs\LaravelModelCaching\CachedBuilder^ {#1391
      #query: Illuminate\Database\Query\Builder^ {#1393
        +connection: Illuminate\Database\MySqlConnection^ {#278}
        +grammar: Illuminate\Database\Query\Grammars\MySqlGrammar^ {#279}
        +processor: Illuminate\Database\Query\Processors\MySqlProcessor^ {#280}
        +bindings: array:7 [
          "select" => []
          "from" => []
          "join" => []
          "where" => array:10 [ …10]
          "having" => []
          "order" => []
          "union" => []
        ]
        +aggregate: null
        +columns: array:7 [
          0 => "orders.*"
          1 => Illuminate\Database\Query\Expression^ {#1369 …1}
          2 => Illuminate\Database\Query\Expression^ {#1372 …1}
          3 => Illuminate\Database\Query\Expression^ {#1377 …1}
          4 => Illuminate\Database\Query\Expression^ {#1376 …1}
          5 => Illuminate\Database\Query\Expression^ {#1387 …1}
          6 => Illuminate\Database\Query\Expression^ {#1389 …1}
        ]
        +distinct: false
        +from: "orders"
        +joins: array:2 [
          0 => Illuminate\Database\Query\JoinClause^ {#1381 …28}
          1 => Illuminate\Database\Query\JoinClause^ {#1386 …28}
        ]
        +wheres: array:5 [
          0 => array:3 [ …3]
          1 => array:5 [ …5]
          2 => array:3 [ …3]
          3 => array:3 [ …3]
          4 => array:5 [ …5]
        ]
        +groups: array:1 [
          0 => "orders.id"
        ]
        +havings: null
        +orders: array:3 [
          0 => array:2 [ …2]
          1 => array:2 [ …2]
          2 => array:2 [ …2]
        ]
        +limit: 11
        +offset: 40
        +unions: null
        +unionLimit: null
        +unionOffset: null
        +unionOrders: null
        +lock: null
        +operators: array:30 [
          0 => "="
          1 => "<"
          2 => ">"
          3 => "<="
          4 => ">="
          5 => "<>"
          6 => "!="
          7 => "<=>"
          8 => "like"
          9 => "like binary"
          10 => "not like"
          11 => "ilike"
          12 => "&"
          13 => "|"
          14 => "^"
          15 => "<<"
          16 => ">>"
          17 => "rlike"
          18 => "not rlike"
          19 => "regexp"
          20 => "not regexp"
          21 => "~"
          22 => "~*"
          23 => "!~"
          24 => "!~*"
          25 => "similar to"
          26 => "not similar to"
          27 => "not ilike"
          28 => "~~*"
          29 => "!~~*"
        ]
        +useWritePdo: false
      }
      #model: App\Order^ {#1367}
      #eagerLoad: []
      #localMacros: array:4 [
        "restore" => Closure(Builder $builder)^ {#1366 …4}
        "withTrashed" => Closure(Builder $builder, $withTrashed = true)^ {#1365 …4}
        "withoutTrashed" => Closure(Builder $builder)^ {#1362 …4}
        "onlyTrashed" => Closure(Builder $builder)^ {#1346 …4}
      ]
      #onDelete: Closure(Builder $builder)^ {#271}
      #passthru: array:17 [
        0 => "insert"
        1 => "insertOrIgnore"
        2 => "insertGetId"
        3 => "insertUsing"
        4 => "getBindings"
        5 => "toSql"
        6 => "dump"
        7 => "dd"
        8 => "exists"
        9 => "doesntExist"
        10 => "count"
        11 => "min"
        12 => "max"
        13 => "avg"
        14 => "average"
        15 => "sum"
        16 => "getConnection"
      ]
      #scopes: array:7 [
        "Illuminate\Database\Eloquent\SoftDeletingScope" => Illuminate\Database\Eloquent\SoftDeletingScope {#411}
        "Scopes\RecentScope" => Scopes\RecentScope^ {#412}
        "Scopes\RestrictByCompany" => Scopes\RestrictByCompany^ {#413}
        "with_created_user" => Scopes\ScopeWithCreatedUser^ {#1358}
        "with_contact" => Scopes\ScopeWithContact^ {#1368}
        "restrict_drafts_and_cart" => Scopes\RestrictDraftsAndCart^ {#1378}
        "comment_count" => Scopes\ScopeWithCommentCount^ {#1371}
      ]
      #removedScopes: []
      #isCachable: true
      #scopesAreApplied: true
      #macroKey: ""
    }
    "type" => "->"
    "args" => array:1 [
      0 => Closure(self $builder)^ {#1394
        class: "Illuminate\Database\Eloquent\Builder"
        this: GeneaLabs\LaravelModelCaching\CachedBuilder^ {#1361}
        use: { …1}
        file: "./vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php"
        line: "969 to 983"
      }
    ]
  ]
  68 => array:7 [
    "file" => "/home/myproject/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php"
    "line" => 1008
    "function" => "Illuminate\Database\Eloquent\{closure}"
    "class" => "Illuminate\Database\Eloquent\Builder"
    "object" => GeneaLabs\LaravelModelCaching\CachedBuilder^ {#1361}
    "type" => "->"
    "args" => array:1 [
      0 => GeneaLabs\LaravelModelCaching\CachedBuilder^ {#1391}
    ]
  ]
  69 => array:7 [
    "file" => "/home/myproject/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php"
    "line" => 981
    "function" => "apply"
    "class" => "Scopes\ScopeWithCreatedUser"
    "object" => Scopes\ScopeWithCreatedUser^ {#1358}
    "type" => "->"
    "args" => array:2 [
      0 => GeneaLabs\LaravelModelCaching\CachedBuilder^ {#1391}
      1 => App\Order^ {#1367}
    ]
  ]
  70 => array:7 [
    "file" => "/home/myproject/app/Scopes/ScopeWithCreatedUser.php"
    "line" => 15
    "function" => "__call"
    "class" => "GeneaLabs\LaravelModelCaching\CachedBuilder"
    "object" => GeneaLabs\LaravelModelCaching\CachedBuilder^ {#1391}
    "type" => "->"
    "args" => array:2 [
      0 => "join"
      1 => array:4 [
        0 => Illuminate\Database\Query\Expression^ {#1395
          #value: "users cu"
        }
        1 => "cu.id"
        2 => "="
        3 => "orders.created_by"
      ]
    ]
  ]
  71 => array:7 [
    "file" => "/home/myproject/vendor/genealabs/laravel-model-caching/src/Traits/Caching.php"
    "line" => 22
    "function" => "__call"
    "class" => "Illuminate\Database\Eloquent\Builder"
    "object" => GeneaLabs\LaravelModelCaching\CachedBuilder^ {#1391}
    "type" => "->"
    "args" => array:2 [
      0 => "join"
      1 => array:4 [
        0 => Illuminate\Database\Query\Expression^ {#1395}
        1 => "cu.id"
        2 => "="
        3 => "orders.created_by"
      ]
    ]
  ]
  72 => array:7 [
    "file" => "/home/myproject/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php"
    "line" => 1356
    "function" => "forwardCallTo"
    "class" => "Illuminate\Database\Eloquent\Builder"
    "object" => GeneaLabs\LaravelModelCaching\CachedBuilder^ {#1391}
    "type" => "->"
    "args" => array:3 [
      0 => Illuminate\Database\Query\Builder^ {#1393}
      1 => "join"
      2 => array:4 [
        0 => Illuminate\Database\Query\Expression^ {#1395}
        1 => "cu.id"
        2 => "="
        3 => "orders.created_by"
      ]
    ]
  ]
  73 => array:7 [
    "file" => "/home/myproject/vendor/laravel/framework/src/Illuminate/Support/Traits/ForwardsCalls.php"
    "line" => 23
    "function" => "join"
    "class" => "Illuminate\Database\Query\Builder"
    "object" => Illuminate\Database\Query\Builder^ {#1393}
    "type" => "->"
    "args" => array:4 [
      0 => Illuminate\Database\Query\Expression^ {#1395}
      1 => "cu.id"
      2 => "="
      3 => "orders.created_by"
    ]
  ]
]

Environment

mikebronner commented 5 years ago

@mycarrysun Thanks for reporting this. This has critical performance implications, so I'll try to look into it as soon as possible, but might not be before the weekend. I'm pretty swamped this week.

mycarrysun commented 5 years ago

No worries - for me specifically I have rolled back to a forked version so am fine for now. Can't speak for others though

mikebronner commented 5 years ago

@mycarrysun Does the forked version include a fix?

mycarrysun commented 5 years ago

No it is just a previous version before the change that introduced the bug. Not sure where the bug is happening.

mikebronner commented 5 years ago

Can you link the fork? That might help me identify when the bug was introduced.

mycarrysun commented 5 years ago

https://github.com/mycarrysun/laravel-model-caching

Here you go :)

mikebronner commented 4 years ago

@mycarrysun Thanks for the link to the fork. That helps. Would you be able to also provide me with your global scope declarations and your complete Order model? Thanks!

mycarrysun commented 4 years ago

@mikebronner sorry man - can't provide the complete Order model but I can provide some relevant code including the global scopes on Order

mycarrysun commented 4 years ago
// These scopes are global scopes applied to the Order model
namespace Scopes;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;
class RecentScope implements Scope
{
    public function apply(Builder $builder, Model $model)
    {
        $builder->orderBy($model->getTable().'.id', 'DESC');
    }
}

//

namespace Scopes;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;
use Illuminate\Support\Facades\Auth;
class RestrictByCompany implements Scope
{
    public function apply(Builder $builder, Model $model)
    {
        if ($user = Auth::user()) {
            if ($user->is_customer) {
                return $builder->where($model->getTable().'.company_id', $user->company_id);
            }
        }
        return $builder;
    }
}

Here is the call where I create the query:

Order::with(Order::$RELATIONS[$relations])
                      ->selectAll()
                      ->withCompany()
                      ->withGlobalScope('with_created_user', new ScopeWithCreatedUser)
                      ->withGlobalScope('with_contact', new ScopeWithContact)
                      ->when($user->is_customer, function ($query) {
                          return $query->withGlobalScope('restrict_drafts_and_cart', new RestrictDraftsAndCart);
                      })
                      ->withCarrierCount()
                      ->withCommentCount();

Here are the relevant scopes for that call:

class ScopeWithCreatedUser implements Scope
{
    public function apply(Builder $query, Model $model)
    {
        return $query->join(\DB::raw('users cu'), 'cu.id', '=', $model->getTable().'.created_by')
                     ->addSelect(\DB::raw('concat(coalesce(cu.first_name, ""), " ", coalesce(cu.last_name, "")) as created_by_name'));
    }
}

class ScopeWithContact implements Scope
{
    public function apply(Builder $query, Model $model)
    {
        return $query->selectSub(function ($query) use ($model) {
            return $query->select([DB::raw('CONCAT(COALESCE(users.first_name, ""), " ", COALESCE(users.last_name, "")) as contact_name')])
                         ->from('users')
                         ->where('users.id', DB::raw($model->getTable().'.contact_id'));
        }, 'contact_name');
    }
}

class RestrictDraftsAndCart implements Scope
{
    public function apply(Builder $builder, Model $model)
    {
        if ($user = Auth::user()) {
            $account_types = [User::CUSTOMER, User::CUSTOMER_ADMIN];
            if ($user->is_staff) {
                return $builder;
            }
            return $builder->where(function ($query) use ($model, $account_types) {
                return $query->whereIn($model->getTable().'.status_id', ['draft', 'in_cart', 'staff_cart'])
                             ->whereIn(DB::raw('(select users.account_type_id from users where users.id = '
                                 .$model->getTable()
                                 .'.created_by)'), $account_types);
            })->orWhereNotIn($model->getTable().'.status_id', ['draft', 'in_cart', 'staff_cart']);
        }
        return $builder;
    }
}

Now scopes on the Order model:

public function scopeWithCarrierCount($query)
    {
        return $query->selectSub(function ($query) {
            return $query->select(DB::raw('count(distinct permits.carrier_id)'))
                         ->from('permits')
                         ->where('permits.order_id', DB::raw('orders.id'))
                         ->whereNull('permits.deleted_at');
        }, 'carrier_count');
    }

More relevant scopes:

class ScopeWithCommentCount implements Scope
{
    /**
     * Get the `comment_count` and `important` properties
     *
     * @param  Builder  $query
     * @param  Model  $model
     *
     * @return Builder|\Illuminate\Database\Query\Builder
     */
    public function apply(Builder $query, Model $model)
    {
        $user = Auth::user();
        return $query->leftJoin('comments', DB::raw('(comments.commentable_type'), '=', DB::raw('"'
            .Helpers::getModelRelationName($model)
            .'" and comments.commentable_id = '
            .$model->getTable()
            .'.id and comments.deleted_at is null'.($user && $user->is_customer ? ' and comments.private = 0' : '')
            .')'))
                     ->addSelect(DB::raw('count(distinct comments.id) as comment_count'))
                     ->addSelect(DB::raw('(select count(distinct comments.id) as important where comments.important = 1 limit 1) as important'))
                     ->groupBy($model->getTable().'.id');
    }
}

The only scope not posted here is the withCompany() and it is a simple inner join on the company_id column.

Hope this helps

saernz commented 4 years ago

I've also just ran into the same bug. It looks like it's just because Eloquent reapply the scopes after the closure in retrieveCachedValue calls the parent's get() method on the eloquent builder. There does not appear to be any checks in place by eloquent to avoid reapplying the scopes as I guess they don't expect them to be already applied. So the scopes first get applied after calling makeCacheKey() then get reapplied later by eloquent in their get() method of their builder. This could possibly be fixed if Buildable overrides the eloquent builders applyScopes() method and just wrapped the parent function in an if which checks the scopesAreApplied variable, if they're applied just return the builder if they're not applied pass through to parent.

mikebronner commented 4 years ago

@saernz @mycarrysun Would you guys try this again with version 0.8.7 or greater? Thanks @saernz for posting the solution!

mycarrysun commented 4 years ago

@saernz @mycarrysun Would you guys try this again with version 0.8.7 or greater? Thanks @saernz for posting the solution!

Unfortunately I don't work at the company where we used this package but hopefully @saernz can test. Looks like his unit tests covered it pretty well though.

mikebronner commented 4 years ago

Sorry to hear that @mycarrysun. All the best to you in your future positions!

saernz commented 4 years ago

@mikebronner Sorry only just seen this. I tested it out straight away after your merge, working well as far as I can tell. I'm on 0.8.8. I will be merging into staging then prod very soon. I actually needed this fix so I could reenable the package in prod again.

mikebronner commented 4 years ago

@saernz Awesome, keep me posted. :)