cviebrock / eloquent-taggable

Easily add the ability to tag your Eloquent models in Laravel.
MIT License
537 stars 72 forks source link

isNotTagged results to QueryException because static::class is escaped instead of treated as string #58

Closed jcsoriano closed 7 years ago

jcsoriano commented 7 years ago

Hi! Thank you for the wonderful package. Makes working with tags very easy to do. However, I'm having a problem with the scopes.

Environment

Eloquent-Taggable version: 3.0.0 Laravel version: 5.4.35 PHP version: 7.0.9 MySQL version: 5.7.14

Description

When I call isNotTagged() scope, I get QueryException because static::class is wrongly escaped. See the error message:

Next Illuminate\Database\QueryException: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'App\Models\Content\Post' in 'on clause' (SQL: select `posts`.* from `posts` left join `taggable_taggables` on `posts`.`id` = `taggable_taggables`.`taggable_id` and `taggable_taggables`.`taggable_type` = `App\Models\Content\Post` where `posts`.`is_draft` = 0 and `posts`.`published_at` <= 2017-08-27 12:57:09 and `posts`.`deleted_at` is null group by `posts`.`id` having COUNT(DISTINCT taggable_taggables.taggable_id) = 0 order by `posts`.`published_at` desc) in C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Database\Connection.php:647

Stack Trace:

Next Illuminate\Database\QueryException: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'App\Models\Content\Post' in 'on clause' (SQL: select `posts`.* from `posts` left join `taggable_taggables` on `posts`.`id` = `taggable_taggables`.`taggable_id` and `taggable_taggables`.`taggable_type` = `App\Models\Content\Post` where `posts`.`is_draft` = 0 and `posts`.`published_at` <= 2017-08-27 12:57:09 and `posts`.`deleted_at` is null group by `posts`.`id` having COUNT(DISTINCT taggable_taggables.taggable_id) = 0 order by `posts`.`published_at` desc) in C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Database\Connection.php:647
Stack trace:
#0 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Database\Connection.php(607): Illuminate\Database\Connection->runQueryCallback('select `posts`....', Array, Object(Closure))
#1 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Database\Connection.php(326): Illuminate\Database\Connection->run('select `posts`....', Array, Object(Closure))
#2 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Database\Query\Builder.php(1705): Illuminate\Database\Connection->select('select `posts`....', Array, true)
#3 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Database\Query\Builder.php(1690): Illuminate\Database\Query\Builder->runSelect()
#4 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Database\Eloquent\Builder.php(462): Illuminate\Database\Query\Builder->get(Array)
#5 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Database\Eloquent\Builder.php(446): Illuminate\Database\Eloquent\Builder->getModels(Array)
#6 C:\wamp\www\MagisGit\gamegulp_new\app\Http\Controllers\Magis\Migrations\TagsController.php(36): Illuminate\Database\Eloquent\Builder->get()
#7 [internal function]: App\Http\Controllers\Magis\Migrations\TagsController->show()
#8 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Routing\Controller.php(55): call_user_func_array(Array, Array)
#9 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Routing\ControllerDispatcher.php(44): Illuminate\Routing\Controller->callAction('show', Array)
#10 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Routing\Route.php(203): Illuminate\Routing\ControllerDispatcher->dispatch(Object(Illuminate\Routing\Route), Object(App\Http\Controllers\Magis\Migrations\TagsController), 'show')
#11 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Routing\Route.php(160): Illuminate\Routing\Route->runController()
#12 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Routing\Router.php(572): Illuminate\Routing\Route->run()
#13 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Routing\Pipeline.php(30): Illuminate\Routing\Router->Illuminate\Routing\{closure}(Object(Illuminate\Http\Request))
#14 C:\wamp\www\MagisGit\gamegulp_new\app\Magis\Middleware\EnforceDevelopmentEnv.php(23): Illuminate\Routing\Pipeline->Illuminate\Routing\{closure}(Object(Illuminate\Http\Request))
#15 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Pipeline\Pipeline.php(148): App\Magis\Middleware\EnforceDevelopmentEnv->handle(Object(Illuminate\Http\Request), Object(Closure))
#16 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Routing\Pipeline.php(53): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#17 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Routing\Middleware\SubstituteBindings.php(41): Illuminate\Routing\Pipeline->Illuminate\Routing\{closure}(Object(Illuminate\Http\Request))
#18 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Pipeline\Pipeline.php(148): Illuminate\Routing\Middleware\SubstituteBindings->handle(Object(Illuminate\Http\Request), Object(Closure))
#19 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Routing\Pipeline.php(53): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#20 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Auth\Middleware\Authenticate.php(43): Illuminate\Routing\Pipeline->Illuminate\Routing\{closure}(Object(Illuminate\Http\Request))
#21 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Pipeline\Pipeline.php(148): Illuminate\Auth\Middleware\Authenticate->handle(Object(Illuminate\Http\Request), Object(Closure))
#22 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Routing\Pipeline.php(53): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#23 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Foundation\Http\Middleware\VerifyCsrfToken.php(65): Illuminate\Routing\Pipeline->Illuminate\Routing\{closure}(Object(Illuminate\Http\Request))
#24 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Pipeline\Pipeline.php(148): Illuminate\Foundation\Http\Middleware\VerifyCsrfToken->handle(Object(Illuminate\Http\Request), Object(Closure))
#25 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Routing\Pipeline.php(53): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#26 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\View\Middleware\ShareErrorsFromSession.php(49): Illuminate\Routing\Pipeline->Illuminate\Routing\{closure}(Object(Illuminate\Http\Request))
#27 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Pipeline\Pipeline.php(148): Illuminate\View\Middleware\ShareErrorsFromSession->handle(Object(Illuminate\Http\Request), Object(Closure))
#28 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Routing\Pipeline.php(53): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#29 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Session\Middleware\StartSession.php(64): Illuminate\Routing\Pipeline->Illuminate\Routing\{closure}(Object(Illuminate\Http\Request))
#30 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Pipeline\Pipeline.php(148): Illuminate\Session\Middleware\StartSession->handle(Object(Illuminate\Http\Request), Object(Closure))
#31 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Routing\Pipeline.php(53): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#32 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse.php(37): Illuminate\Routing\Pipeline->Illuminate\Routing\{closure}(Object(Illuminate\Http\Request))
#33 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Pipeline\Pipeline.php(148): Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse->handle(Object(Illuminate\Http\Request), Object(Closure))
#34 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Routing\Pipeline.php(53): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#35 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Cookie\Middleware\EncryptCookies.php(59): Illuminate\Routing\Pipeline->Illuminate\Routing\{closure}(Object(Illuminate\Http\Request))
#36 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Pipeline\Pipeline.php(148): Illuminate\Cookie\Middleware\EncryptCookies->handle(Object(Illuminate\Http\Request), Object(Closure))
#37 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Routing\Pipeline.php(53): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#38 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Pipeline\Pipeline.php(102): Illuminate\Routing\Pipeline->Illuminate\Routing\{closure}(Object(Illuminate\Http\Request))
#39 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Routing\Router.php(574): Illuminate\Pipeline\Pipeline->then(Object(Closure))
#40 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Routing\Router.php(533): Illuminate\Routing\Router->runRouteWithinStack(Object(Illuminate\Routing\Route), Object(Illuminate\Http\Request))
#41 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Routing\Router.php(511): Illuminate\Routing\Router->dispatchToRoute(Object(Illuminate\Http\Request))
#42 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Foundation\Http\Kernel.php(176): Illuminate\Routing\Router->dispatch(Object(Illuminate\Http\Request))
#43 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Routing\Pipeline.php(30): Illuminate\Foundation\Http\Kernel->Illuminate\Foundation\Http\{closure}(Object(Illuminate\Http\Request))
#44 C:\wamp\www\MagisGit\gamegulp_new\vendor\barryvdh\laravel-debugbar\src\Middleware\Debugbar.php(51): Illuminate\Routing\Pipeline->Illuminate\Routing\{closure}(Object(Illuminate\Http\Request))
#45 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Pipeline\Pipeline.php(148): Barryvdh\Debugbar\Middleware\Debugbar->handle(Object(Illuminate\Http\Request), Object(Closure))
#46 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Routing\Pipeline.php(53): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#47 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Foundation\Http\Middleware\TransformsRequest.php(30): Illuminate\Routing\Pipeline->Illuminate\Routing\{closure}(Object(Illuminate\Http\Request))
#48 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Pipeline\Pipeline.php(148): Illuminate\Foundation\Http\Middleware\TransformsRequest->handle(Object(Illuminate\Http\Request), Object(Closure))
#49 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Routing\Pipeline.php(53): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#50 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Foundation\Http\Middleware\TransformsRequest.php(30): Illuminate\Routing\Pipeline->Illuminate\Routing\{closure}(Object(Illuminate\Http\Request))
#51 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Pipeline\Pipeline.php(148): Illuminate\Foundation\Http\Middleware\TransformsRequest->handle(Object(Illuminate\Http\Request), Object(Closure))
#52 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Routing\Pipeline.php(53): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#53 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Foundation\Http\Middleware\ValidatePostSize.php(27): Illuminate\Routing\Pipeline->Illuminate\Routing\{closure}(Object(Illuminate\Http\Request))
#54 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Pipeline\Pipeline.php(148): Illuminate\Foundation\Http\Middleware\ValidatePostSize->handle(Object(Illuminate\Http\Request), Object(Closure))
#55 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Routing\Pipeline.php(53): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#56 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode.php(46): Illuminate\Routing\Pipeline->Illuminate\Routing\{closure}(Object(Illuminate\Http\Request))
#57 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Pipeline\Pipeline.php(148): Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode->handle(Object(Illuminate\Http\Request), Object(Closure))
#58 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Routing\Pipeline.php(53): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#59 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Pipeline\Pipeline.php(102): Illuminate\Routing\Pipeline->Illuminate\Routing\{closure}(Object(Illuminate\Http\Request))
#60 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Foundation\Http\Kernel.php(151): Illuminate\Pipeline\Pipeline->then(Object(Closure))
#61 C:\wamp\www\MagisGit\gamegulp_new\vendor\laravel\framework\src\Illuminate\Foundation\Http\Kernel.php(116): Illuminate\Foundation\Http\Kernel->sendRequestThroughRouter(Object(Illuminate\Http\Request))
#62 C:\wamp\www\MagisGit\gamegulp_new\public\index.php(53): Illuminate\Foundation\Http\Kernel->handle(Object(Illuminate\Http\Request))
#63 {main}  

Steps to Reproduce:

  1. Put Taggable trait in model class
  2. Call [Model]::isNotTagged()->get();

[EDIT] Workaround:

  1. I worked around this by using [Model]::doesntHave('tags')->get();

What is the advantage of isNotTagged() vs doesntHave('tags')? (https://laravel.com/docs/5.4/eloquent-relationships#querying-relations)

cviebrock commented 7 years ago

isNotTagged() uses code from my package, whereas doesntHave('tags') uses code built in to Eloquent. The end result should be identical, although the SQL isn't very well optimized when you use doesntHave(). If you have a lot of models and/or a lot of tags, you will notice this.

That said, I can't seem to reproduce your issue. In fact, I have a test for isNotTagged() that seems to pass just fine and doesn't throw the exception you noted.

If possible, could you fork the repo, and write another test method in tests/ScopeTests.php that fails? I can take it from there.

Corys8646 commented 7 years ago

Still digging into it, but I upgraded one of my sites to 5.5 and am seeing the same problem when using Model::withAnyTags() and Model::withAllTags()

SQLSTATE[42S22]: Column not found: 1054 Unknown column 'App\Models\Article' in 'on clause' (SQL: select 'archive_articles'.* from 'archive_articles' inner join 'taggable_taggables' on 'archive_articles'.'article_id' = 'taggable_taggables'.'taggable_id' and 'taggable_taggables'.'taggable_type' = 'App\Models\Article' where 'taggable_taggables'.'tag_id' in (1) group by 'archive_articles'.'article_id')

cviebrock commented 7 years ago

I think I figured it out. Can you check the dev-refactor-sql version and let me know if that fixes it?

Corys8646 commented 7 years ago

That did the job. Thanks!

cviebrock commented 7 years ago

Thanks! I'll push a new version out shortly.

cviebrock commented 7 years ago

3.1.2 for Laravel 5.4, and 3.2.2. for Laravel 5.5. Thanks for the help!