Laravel神秘-两个相似的项类型在同一用例中产生两个不同的查询字符串

Laravel神秘-两个相似的项类型在同一用例中产生两个不同的查询字符串,laravel,Laravel,好吧,这很奇怪。。。准备好了吗 我的网站上有一个项目类型,我们把它叫做SomeItem 它可以通过一对多关系将标记与之关联 在处理SomeItem的标记时,Laravel构建的查询类型如下,例如响应routeapi/SomeItem/10: select `tags`.*, `someitem_tag`.`someitem_id` as `pivot_someitem_id`, `someitem_tag`.`tag_id` as `pivot_tag_id` from `tags` inner

好吧,这很奇怪。。。准备好了吗

我的网站上有一个项目类型,我们把它叫做
SomeItem

它可以通过一对多关系将
标记与之关联

在处理
SomeItem
的标记时,Laravel构建的查询类型如下,例如响应route
api/SomeItem/10

select `tags`.*, `someitem_tag`.`someitem_id` as `pivot_someitem_id`, `someitem_tag`.`tag_id` as `pivot_tag_id` from `tags` inner join `someitem_tag` on `tags`.`id` = `someitem_tag`.`tag_id` where `someitem_tag`.`someitem_id` in (10)
当我创建具有相同设置的第二个项时(我们称之为
其他项
),它以不同的方式处理数据库查询以提取
标记
,在查询中使用不同的语法。非常奇怪。

(是的,我在型号名称的末尾有一个
s

例如,此路由
api/anotheritems/1

产生以下错误:

Base table or view not found: 1146 Table 'mysite.tag_anotheritems' doesn't exist (SQL: select `tags`.*, `tag_anotheritems`.`anotheritems_id` as `pivot_anotheritems_id`, `tag_anotheritems`.`tag_id` as `pivot_tag_id` from `tags` inner join `tag_anotheritems` on `tags`.`id` = `tag_anotheritems`.`tag_id` where `tag_anotheritems`.`anotheritems_id` in (1))
看看发生了什么?当然,我得到了这个错误-在数据库中,
AnotherItems
的这个标记表被创建为
AnotherItems\u tag
。这类似于
SomeItem

Laravel究竟是如何对一个项目使用语法
someitem\u tag
,而对另一个项目使用语法
tag\u anotheritems

首先,让我向您展示如何设置
SomeItem

以下是与标记相关的数据库结构:

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateSomeItemTagTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('someitem_tag', function (Blueprint $table) {
            $table->integer('tag_id')->unsigned();
            $table->foreign('tag_id')->references('id')->on('tags')->onDelete('cascade');

            $table->integer('someitem_id')->unsigned();
            $table->foreign('someitem_id')->references('id')->on('someitems')->onDelete('cascade');

            $table->primary(array('tag_id', 'someitem_id'));
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::drop('someitem_tag');
    }
}
有一个标记模型/类具有以下特性:

namespace App;

use Illuminate\Database\Eloquent\Model;

class Tag extends Model
{
    protected $fillable = ['name'];
    protected $hidden = [];
    public $timestamps = false;

    public function someitems()
    {
        return $this->belongsToMany(SomeItem::class);
    }

}

以下是一些项目模型/类别的相关行:

namespace App;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
use App\Presenters\Presentable;
use Illuminate\Notifications\Notifiable;
use Auth;

class Exercise extends Model
    implements Presentable
{
    use Traits\SerializesUniversalDate;
    use Traits\Presents;
    use Notifiable;

    protected $presenter = 'App\Presenters\SomeItemPresenter';
    protected $fillable = ['title', etc];
    protected $hidden = [];

    public function parentitem()
    {
        return $this->belongsTo(ParentItem::class);
    }

    public function tags()
    {
        return $this->belongsToMany(Tag::class);
    }

    /**
     * Update lesson tag array.
     *
     * @param  array    \App\Tag  $tags
     * @return void
     */
    public function updateTags($tagsArray)
    {
        foreach ($tagsArray as &$value)
        {
            $tag = Tag::where('name', $value['name'])->first();
            if (is_null($tag))
            {
                $tag = new Tag([
                    'name' => $value['name']
                ]);
                $tag->save();
            }
            if (!$this->tags->contains($tag->id))
            {
                $this->tags()->attach($tag->id);
            }
        }
        foreach($this->tags as &$existingTag)
        {
            if (!self::arrayContains($tagsArray, 'name', $existingTag->name))
            {
                $this->tags()->detach($existingTag->id);
            }
        }
        $this->load('tags');
    }


    private static function arrayContains($array, $key, $value)
    {
        foreach ($array as $item)
        {
            if($item[$key] == $value) return true;
        }
        return false;
    }

}
下面是SomeItem API控制器的一些相关代码:

namespace App\Http\Controllers\Api;

use Illuminate\Http\Request;

use App\Http\Requests;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Input;

class SomeItemController extends Controller
{
    public function index(Request $request)
    {
        $query = \App\SomeItem::query();

        return $query->get()->load('parentitem')->load('tags');
    }

    //show item for editing
    public function show($id)
    {

        $someitem = \App\SomeItem::find($id);

        $someitem->load('parentitem')->load('tags');
        $someitem->attachKindToFiles();
        return $someitem;


    }

    //store new entry to db

    public function store()
    {
        $someitem = \App\SomeItem::create(Input::all());
        isset(Input::all()['tags']) ? $someitem->updateTags(Input::all()['tags']) : '';
        return $someitem;
    }

    //update/save
    public function update($id)
    {
        $someitem = \App\SomeItem::find($id);
        $someitem->update(Input::all());
        $someitem->updateTags(Input::all()['tags']);
        $someitem->load('tags');
        return $someitem;
    }

还有一个SomeItem presenter和composer,但它们不使用标记

使用
其他项
,我复制了
某个项
中的所有内容,并根据需要更改名称

因此,在标记模型中存在

public function anotheritems()
    {
        return $this->belongsToMany(AnotherItems::class);
    }
例如,在
另一个项目
模型中就有这样一个项目

    public function tags()
    {
        return $this->belongsToMany(Tag::class);
    }
例如,在
AnotherItems
API控制器中(用于路由API/AnotherItems/1):

所以,这完全是个谜。我两天来一直在想这个问题。我继续问自己

Laravel究竟是如何为一个项目使用语法
someitem\u tag
,而为另一个项目使用语法
tag\u anotheritems

我从laravel 5.2升级到了5.3,在升级之后,我添加了这个
其他项
。但我不知道这如何可能改变这些数据库查询的情况

我尝试了大量artisan命令来清除所有可以想象的内容,但在框架中的某个地方,它希望在构建这些连接查询以提取/保存标记时,以不同的方式处理
SomeItem
anotheritem

想法

谢谢, 布莱恩



决定在调试器中单步执行代码。似乎Str.php中的各种
snake
相关函数出现了故障,我还注意到了snakeCache调用,不管是什么。不知道为什么用这种奇怪的方法来确定表名。。。在这些函数中还有一些复数相关检查,因此这可能与我在项目名称末尾使用
s
有关。如果一个模型名称末尾的s会导致两个不同的逻辑分支,那就相当糟糕了…

好吧,我把表名改成了
tag\u anotheritems
,一切正常,但这真的是一团糟,不是我想求助的解决方案。如果模型的名称会导致Laravel以两种不同的方式确定联接表的名称,可能是基于复数化与非复数化,那么这意味着逻辑是错误的。也许它在以后版本的Laravel中得到了修复。但是说真的,我们应该能够调用模型,不管他们想要什么(在合理的范围内),并且不必担心这样的命名实际上会破坏查询生成器中的某些东西<代码>返回$this->belongToMany(AnotherItem::class,“anotheritems_标记”)
和您的
另一个项目
类也是如此。问题是,我与这个新项目有一些其他的一对多关系,我只是更改了表名,一切正常。我不想编辑代码,因为跟踪表名比修改代码更容易。但我想我会编辑Laravel5.3的源代码,这样就不会发生这种情况,并跟踪编辑过程。如果这对你来说更简单,就这么做吧!另一个注意事项:阅读您的标签系统,我认为这可能是一个好主意。:)好的,我将表名更改为
标记其他项
,一切正常,但这真的是一团糟,不是我想要的解决方案。如果模型的名称会导致Laravel以两种不同的方式确定联接表的名称,可能是基于复数化与非复数化,那么这意味着逻辑是错误的。也许它在以后版本的Laravel中得到了修复。但是说真的,我们应该能够调用模型,不管他们想要什么(在合理的范围内),并且不必担心这样的命名实际上会破坏查询生成器中的某些东西<代码>返回$this->belongToMany(AnotherItem::class,“anotheritems_标记”)和您的
另一个项目
类也是如此。问题是,我与这个新项目有一些其他的一对多关系,我只是更改了表名,一切正常。我不想编辑代码,因为跟踪表名比修改代码更容易。但我想我会编辑Laravel5.3的源代码,这样就不会发生这种情况,并跟踪编辑过程。如果这对你来说更简单,就这么做吧!另一个注意事项:阅读您的标签系统,我认为这可能是一个好主意。:)
 public function index(Request $request)
    {

        $query = \App\AnotherItems::query();

        if ($request->has('id')) {
            $query->where('id', $request['id']);
        }

        return $query->get()->load('parentitem')->load('tags');
    }