简体   繁体   中英

How to create a hasManyThrough relation in Laravel?

I am trying to create a hasManyThrough in Laravel for my tables.

Here is a high level of my table structure

I have survey_questions table. (one question belongs to many controls survey_questions.id = survey_question_controls.question_id )

I have survey_question_controls table (many controls belong to one question ie survey_question_controls.question_id = survey_questions.id )

I also have survey_control_items (many items belong to one control ie survey_control_items.control_id = survey_question_controls.id )

I need to build a hasManyThrough relation for the question to the items.

Here are my table definitions

CREATE TABLE `survey_questions` (
   `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
   `title` varchar(120) COLLATE utf8_unicode_ci NOT NULL,
   `survey_id` int(10) unsigned NOT NULL,
   `sort` mediumint(9) NOT NULL DEFAULT '0',
   `page_number` smallint(5) unsigned NOT NULL,
   `is_required` enum('0','1') COLLATE utf8_unicode_ci NOT NULL DEFAULT '0',
   `visible_level` enum('All','store','region','district','division') COLLATE utf8_unicode_ci NOT NULL DEFAULT 'All',
   `visible_to` varchar(120) COLLATE utf8_unicode_ci NOT NULL,
   `visible` enum('Always','conditional') COLLATE utf8_unicode_ci NOT NULL DEFAULT 'Always',
   `status` enum('active','inactive') COLLATE utf8_unicode_ci NOT NULL DEFAULT 'active',
   `created_at` timestamp NULL DEFAULT NULL,
   `updated_at` timestamp NULL DEFAULT NULL,
   PRIMARY KEY (`id`),
   KEY `survey_questions_survey_id_index` (`survey_id`)
 ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

CREATE TABLE `survey_question_controls` (
   `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
   `title` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
   `question_id` int(10) unsigned NOT NULL,
   `input_type` enum('text','textarea','radio','checkbox','menu','list') COLLATE utf8_unicode_ci NOT NULL,
   `sort` mediumint(9) NOT NULL DEFAULT '0',
   `validation_rule` enum('none','number','text') COLLATE utf8_unicode_ci NOT NULL DEFAULT 'none',
   `min_length` int(10) unsigned DEFAULT NULL,
   `max_length` int(10) unsigned DEFAULT NULL,
   `min_value` int(11) DEFAULT NULL,
   `max_value` int(11) DEFAULT NULL,
   `refuse` enum('0','1') COLLATE utf8_unicode_ci NOT NULL DEFAULT '0',
   `disqualify` enum('0','1') COLLATE utf8_unicode_ci NOT NULL DEFAULT '0',
   `status` enum('active','inactive') COLLATE utf8_unicode_ci NOT NULL DEFAULT 'active',
   `created_at` timestamp NULL DEFAULT NULL,
   `updated_at` timestamp NULL DEFAULT NULL,
   PRIMARY KEY (`id`),
   KEY `survey_question_controls_question_id_index` (`question_id`)
 ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

 CREATE TABLE `survey_control_items` (
   `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
   `title` varchar(120) COLLATE utf8_unicode_ci NOT NULL,
   `control_id` int(10) unsigned NOT NULL,
   `sort` mediumint(9) NOT NULL DEFAULT '0',
   `created_at` timestamp NULL DEFAULT NULL,
   `updated_at` timestamp NULL DEFAULT NULL,
   PRIMARY KEY (`id`),
   KEY `survey_control_items_control_id_index` (`control_id`)
 ) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

I am trying to get similar data to this question using the Laravel's ORM.

SELECT * FROM survey_questions AS q
INNER JOIN survey_question_controls AS c ON c.question_id = q.id
LEFT JOIN survey_control_items AS i ON i.control_id = c.id

In my SurveyQuestions model I added this relations

 /**
 * Get items for the controls that belongs to the question
 * Questions > controls > 
 */
public function items()
{
    return $this->hasManyThrough(Surveyquestioncontrols::class, Surveycontrolitems::class, 'question_id', 'id', 'control_id', 'control_id');
}

This is giving me the following SQL error

SQLSTATE[42S22]: Column not found: 1054 Unknown column 'survey_control_items.surveyquestioncontrols_id' in 'where clause' (SQL: select * from `survey_control_items` where `survey_control_items`.`surveyquestioncontrols_id` = 1 and `survey_control_items`.`surveyquestioncontrols_id` is not null)

Question How do I create a hasManyThrough relation?

Edited

When you read the error above you will notice the a column name that does not exists survey_control_items.surveyquestioncontrols_id this column should be survey_control_items.control_id

Additionally, based on the feedback below, my items() method should look like this

 /**
 * Get items for the controls that belongs to the question
 * Questions > controls > 
 */
public function items()
{
    return $this->hasManyThrough(Surveycontrolitems::class, Surveyquestioncontrols::class, 'question_id', 'control_id');
}

This error may be because you are using the hasManyThrough() method incorrectly.

If your model classes are in the namespace 'App', try:

return $this->hasManyThrough('App\Surveycontrolitems', 'App\Surveyquestioncontrols', 'question_id', 'control_id');

Source: Documentation and API Usage

You are using the wrong parameter order for the models

The first argument passed to the hasManyThrough method is the name of the final model we wish to access, while the second argument is the name of the intermediate model.

and for the foreign keys

The third argument is the name of the foreign key on the intermediate model, while the fourth argument is the name of the foreign key on the final model.

public function items()
{
    return $this->hasManyThrough(
        Surveycontrolitems::class,
        Surveyquestioncontrols::class,
        'question_id',
        'control_id'
    );
}

All of this would be automatic if you used proper camel- and snake-casing for your models and database tables and named the foreign keys according to the actual related table names.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM