【问题标题】:Call to undefined method Illuminate\Database\Eloquent\Relations\BelongsTo::type()调用未定义的方法 Illuminate\\Database\\Eloquent\\Relations\\BelongsTo::type() [Laravel]
【发布时间】:2020-01-29 13:33:31
【问题描述】:

我正在尝试制作一个在数据库中创建单词后返回单词类型(名词、代词、动词等)的 api。但是由于某种原因,当我的词汇模型中明确定义了类型方法时,我收到“调用未定义的方法 Illuminate\Database\Eloquent\Relations\BelongsTo::type()”错误。我没有使用多对多关系,而是一对多关系(这就是我使用 hasMany() 和 belongsTo 的原因)。 Type 有很多 Vocabulary 但 Vocabulary 只有一个 Type 和很多 VocabularyContents 并且 VocabularyContent 只有一个与之相关的词汇。所以显然没有多对多的关系。很明显我的问题不是Call to undefined method (laravel 5.2) 的重复。以下是应用程序的部分代码。

第一个模型是类型模型,它允许我获取类型的“内容”(此处未列出模型)和属于特定类型的词汇表。

模型代码清单 1:VocType.php

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class VocType extends Model
{
    public function contents()
    {
        return $this->hasMany('App\VocTypeContent');
    }

    public function vocabularies()
    {
        return $this->hasMany('App\VocVocabulary');
    }
}

第二个模型允许我在词汇表中创建一个词来访问它的“内容”、类型和类别。这就是问题所在。

模型代码清单 2:VocVocabulary.php

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class VocVocabulary extends Model
{
    protected $fillable = ['voc_category_id','type_id', 'name', 'context', 'picture'];
    public $timestamps = false;

    public function contents()
    {
        return $this->hasMany('App\VocVocabularyContent');
    }

    public function type()
    {
        return $this->belongsTo('App\VocType');
    }

    public function category()
    {
        return $this->belongsTo('App\VocCategory');
    }
}

第三个模型允许我创建词汇表的内容并访问它的父词汇表。

模型代码清单 3:VocVocabularyContent.php

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class VocVocabularyContent extends Model
{
    protected $fillable = ['voc_vocabulary_id','lang_id', 'content', 'context', 'romanization', 'pronunciation', 'audio'];
    public $timestamps = false;

    public function vocabulary()
    {
        return $this->belongsTo('App\VocVocabulary');
    }
}

以下是用于上述模型的三个迁移。

迁移代码清单 1:create_voc_types_table.php

<?php

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

class CreateVocTypesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('voc_types', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->string('abbreviation');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('voc_types');
    }
}

迁移代码清单 2:create_voc_vocabularies_table.php

<?php

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

class CreateVocVocabulariesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('voc_vocabularies', function (Blueprint $table) {
            $table->increments('id');
            $table->unsignedInteger('cat_id');
            $table->unsignedInteger('type_id');
            $table->foreign('cat_id')->references('id')->on('voc_categories')->onDelete('cascade');
            $table->foreign('type_id')->references('id')->on('voc_types')->onDelete('cascade');
            $table->string('name');
            $table->string('context');
            $table->string('picture');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('voc_vocabularies');
    }
}

迁移代码清单 3:create_voc_vocabulary_contents_table.php

<?php

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

class CreateVocVocabularyContentsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('voc_vocabulary_contents', function (Blueprint $table) {
            $table->primary(['voc_id', 'lang_id']);
            $table->unsignedInteger('voc_id');
            $table->unsignedInteger('lang_id');
            $table->foreign('voc_id')->references('id')->on('voc_vocabularies')->onDelete('cascade');
            $table->foreign('lang_id')->references('id')->on('languages')->onDelete('cascade');
            $table->string('content');
            $table->string('context');
            $table->string('romanization');
            $table->string('pronunciation');
            $table->string('audio');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('voc_vocabulary_contents');
    }
}

这是我调用词汇表的 type() 方法的控制器。基本上我有一个 html 表单,如果请求中没有提供 id,则会向这个控制器的方法(postVocabularyAPI)发送一个发布请求,一个词汇表将被创建(如果语言是英语)。然后,无论请求是否提供了 id,该方法都会为给定的 id 创建一个词汇表“内容”(如果没有提供 id,则给定的 id 将是先前创建的词汇表的 id)。然后 postVocabularyAPI 方法将返回一个包含词汇类型 id 的 json 响应。

控制器代码清单 1:Vocabulearn.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use App\Language;
use App\VocTheme;
use App\VocCategory;
use App\VocCategoryContent;
use App\VocVocabulary;
use App\VocVocabularyContent;
use App\VocType;

class Vocabulearn extends Controller
{

    //other methods above

    public function postVocabularyAPI(Request $request, $language, $theme, $category){

        $vocabulary_id = $request->vocabulary_id;
        if($vocabulary_id === NULL){
            if($language == "english"){
                $vocabulary = VocVocabulary::create([
                    'voc_category_id'   => VocCategory::where("slug", $category)->get()->first()->id,
                    'type_id'           => VocType::where("abbreviation", $request->type)->get()->first()->id,
                    'name'              => ucfirst(addslashes($request->translation)),
                    'context'           => $request->context,
                    'picture'           => ''
                ]);
                $vocabulary_id = $vocabulary->id;
            } else {
                echo '{"success":false, "message":"Create first the English Vocabulary"}';
            }
        }

        $vocabularyContent = VocVocabularyContent::where('lang_id', '=', Language::where("slug", $language)->get()->first()->id)
        ->where('voc_vocabulary_id', '=', $vocabulary_id)
        ->first();

        if($vocabularyContent !== NULL){
            $vocabularies = DB::table('voc_vocabulary_contents')
            ->where('lang_id', '=', Language::where("slug", $language)->get()->first()->id)
            ->where('voc_vocabulary_id', '=', $vocabulary_id)
            ->delete();
        }

        $vocabularyContent = VocVocabularyContent::create([
            'voc_vocabulary_id' => $vocabulary_id,
            'lang_id' => Language::where("slug", $language)->get()->first()->id,
            'content' => ucfirst(addslashes($translation)),
            'context' => addslashes($context),
            'romanization' => strtolower(addslashes($romanization)),
            'pronunciation' => $pronunciation,
            'audio' => $request->audio
        ]);

        echo '{"success":true, "type":"'.stripslashes(html_entity_decode($vocabularyContent->vocabulary()->type()->id)).'"}';
    }
}

这样做给了我一个

"调用未定义的方法 Illuminate\Database\Eloquent\Relations\BelongsTo::type()"

即使我改变了

echo '{"success":true, "type":"'.stripslashes(html_entity_decode($vocabularyContent->vocabulary()->type()->id)).'"}';

通过

echo '{"success":true, "type":"'.stripslashes(html_entity_decode($vocabularyContent->vocabulary()->get()->first()->type()->id)).'"}';

我收到一条错误提示

“在 null 上调用成员函数 type()”

这是不对的,因为数据库已正确填充,所以我不应该得到一个空词汇。

【问题讨论】:

  • 你确定$vocabularyContent-&gt;vocabulary() 有一个类型吗?您可以通过删除() 直接获取词汇模型,因此此$vocabularyContent-&gt;vocabulary()-&gt;type()-&gt;id 变为$vocabularyContent-&gt;vocabulary-&gt;type-&gt;id
  • @Laravel 我没有使用多对多关系,而是一对多(这就是我使用 hasMany() 和 belongsTo 的原因)。 Type 有很多 Vocabulary 但 Vocabulary 只有一个 Type 和很多 VocabularyContents 并且 VocabularyContent 只有一个与之相关的词汇。很明显没有多对多的关系。
  • 另外我不认为你的关系在你的VocVocabulary 中设置正确你有一个类别关系但关键似乎是voc_category_id 这不是标准的 laravel,你需要指定主要像这样的关键return $this-&gt;hasOne('App\Model', 'foreign_key'); 我认为这适用于您的多个模型。你测试了你所有的关系,它们是否正常工作?
  • @Mike 在 belongsTo 中设置了 foreign_key 成功了!

标签: php laravel laravel-5


【解决方案1】:

对此有一个快速的解决方案。

首先在VocVocabulary模型type函数中添加一个外键

public function type()
{
    return $this->belongsTo('App\VocType', 'type_id');
}

然后去掉括号

echo $vocabularyContent->type->id;

但这不是执行此操作的标准方法。您需要以标准方式设置关系,以帮助 Laravel 理解您的关系。

首先,您需要将函数名称更改为模型名称的 camelCase。例如,由于您的类型模型名称是 VocType,因此您的 type 函数应更改为

public function type()

public function vocType()
{
 return $this->belongsTo('App\VocType'); //you don't need a foreign key here
}

在这种情况下,您告诉 laravel 函数 vocType 的目标是 VocType 模型。此外,您需要将VocVocabulary 表中的外键从type_id 更改为voc_type_id。通过这种方式,Laravel 清楚地了解您的关系,否则您需要付出额外的努力来教 Laravel 关于您的关系。

【讨论】:

    猜你喜欢
    • 2021-03-12
    • 1970-01-01
    • 2018-11-22
    • 2021-03-06
    • 2020-11-23
    • 2020-01-26
    • 2021-06-07
    • 1970-01-01
    • 2020-05-04
    相关资源
    最近更新 更多