Laravel - связывание любого метода с любым экземпляром модели внезапно приводит к ошибке

Итак, внезапно моя среда разработки сломалась, я попытаюсь объяснить, что произошло, по пунктам:

  • Я добавлял новую миграцию и новую модель / контроллер, когда внезапно моя страница перестала загружаться, говоря, что я пытаюсь загрузить не объект.
  • Я пошел проверить внутри php artisan tinker, я попытался запустить обычный запрос, похожий на тот, что на упомянутой странице, например:
  • $p = Product::first();
  • $p->mainCategory; (это метод на Product.php),
  • Обычно он возвращает экземпляр\App\Category.php со всеми своими параметрами (все отношения определены, и они работают правильно), но вместо Я получил возвращенный null;
  • Поэтому я подумал, может быть, у этого продукта нет подходящего Category, но затем я запросил базу данных с category_id, доступным на экземпляре Product, и нашел запись в базе данных.
  • В конце концов, я подумал, что, возможно, новая миграция каким-то образом сломала базу данных, поэтому я удалил базу данных и импортировал дамп sql с сервера (в процессе я также сделал git reset --hard для предыдущего коммита, просто чтобы убедиться, что все как было) .
  • Я повторил тот же запрос снова и снова получил null.
  • Итак, прямо сейчас я могу получить записи из базы данных для моделей, но я не могу, хоть убей, запустить какой-либо метод, доступный для этого экземпляра модели, и, конечно, я не могу получить какие-либо отношения.
  • ВАЖНЫЙ (думаю)
  • Когда я запускаю что-то вроде $p->mainCategory(), я ожидаю экземпляр или belongsTo relationship, вместо я получаю сообщение об ошибке:

BadMethodCallException with message 'Call to undefined method Illuminate\Database\Query\Builder::mainCategory()'

  • МОЖЕТ БЫТЬ - это ключ к решению этой проблемы, потому что, если я попытаюсь связать какой-либо метод с экземпляром модели, как указано выше, я получу эту ошибку.
  • Я не знаю, почему он рассматривается как экземпляр Query \ Builder, это должен быть экземпляр App \ Product
  • Вот где он получает еще более странный, это происходит со всеми моими моделями, кроме одной, которая называется Restaurant.php, это единственная, которую я могу выполнять запросы / добавлять методы в обычном режиме, все остальные сломаны.
  • Ниже я помещу свои Product.php, Restaurant.php и миграцию products_table в качестве справки.

Product.php

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Product extends Model
{
    public function isEnabled()
    {
        return $this->pro_active == 2;
    }

    public function getName()
    {
        return $this->{'pro_name_' . app()->getLocale()};
    }


    public function offer()
    {
        return $this->hasOne( \App\ProductOffer::class );
    }


    public function cats()
    {
        return $this->hasMany( \App\ProductCategory::class );
    }


    public function mainCategory()
    {
        return $this->belongsTo( \App\Category::class, 'pro_main_cat_id', 'id' );
    }


    public function subCat()
    {
        return $this->belongsTo( \App\SubCategory::class, 'pro_sub_cat_id', 'id' );
    }

    public function subsubcategory()
    {
        return $this->belongsTo(\App\Subsubcategory::class, 'pro_sub_sub_cat_id');
    }

Restaurant.php

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Restaurant extends Model
{
    public function products()
    {
        return $this->belongsToMany(\App\Product::class, 'restaurant_products');
    }

    public function orders()
    {
        return $this->hasMany(\App\RestaurantOrder::class);
    }


    public function isAvailable()
    {
        return $this->status == 1;
    }


    public function isOpen()
    {
        return $this->open == 1;
    }


    public function getLogo()
    {
        return $this->logo ?? asset('setting/logo/2018-06-10.logo.jpg');
    }


    public function getName()
    {
        if ( app()->getLocale() == 'ar' ) {
            return $this->name_ar ?? $this->name;
        }

        return $this->name_en ?? $this->name;
    }
}

products_table перенос:

<?php

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

class CreateProductsTable extends Migration {

    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up() {
        Schema::create('products', function (Blueprint $table) {
            $table->increments('id');
            $table->string('pro_special');
            $table->string('pro_active');
            $table->integer('pro_main_cat_id')->nullable();
            $table->integer('pro_sub_cat_id')->nullable();
            $table->integer('pro_sub_sub_cat_id')->nullable();
            $table->integer('pro_country_id')->nullable();
            $table->integer('pro_city_id')->nullable();
            $table->integer('pro_price');
            $table->integer('pro_discount_percentage')->nullable();
            $table->integer('pro_after_discount')->nullable();
            $table->string('pro_image');
            $table->string('pro_name_ar');
            $table->string('pro_name_en');
            $table->string('pro_desc_ar')->nullable();
            $table->string('pro_desc_en')->nullable();
            $table->string('pro_small_desc_ar')->nullable();
            $table->string('pro_small_desc_en')->nullable();
            $table->string('pro_slogen_ar')->nullable();
            $table->string('pro_slogen_en')->nullable();
            $table->string('pro_view')->nullable();
            $table->integer('user_id')->default(0);
            $table->timestamps();
        });
    }

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

}

Как вы можете видеть, это все обычные классы, они должны функционировать одинаково, но по неизвестной причине они просто этого не делают.

Редактировать

Вот dd(Product::first());:

App\Product {#907
  #connection: null
  #table: null
  #primaryKey: "id"
  #keyType: "int"
  #perPage: 15
  +incrementing: true
  +timestamps: true
  #attributes: array:29 [
    "id" => 4
    "pro_special" => "2"
    "pro_active" => "2"
    "pro_main_cat_id" => 2
    "pro_sub_cat_id" => 2
    "pro_sub_sub_cat_id" => 3
    "pro_country_id" => 5
    "pro_city_id" => 7
    "pro_price" => 0.45
    "pro_discount_percentage" => 0
    "pro_after_discount" => 0.0
    "pro_image" => "upload/product/1529115234.Bruot.jpg"
    "pro_name_ar" => "خبز عربي 6 أرغفة"
    "pro_name_en" => "ARABISCHES BROT 6 STÜCK"
    "pro_desc_ar" => "<p>خبز عربي 6 أرغفة</p>\r\n"
    "pro_desc_en" => "<p>ARABISCHES BROT 6 STÜCK</p>\r\n"
    "pro_small_desc_ar" => "الوصف عربى"
    "pro_small_desc_en" => "الوصف المانى"
    "pro_slogen_ar" => "خبز-عربي-6-أرغفة"
    "pro_slogen_en" => "arabisches-brot-6-stck"
    "pro_view" => null
    "user_id" => 0
    "prod_count" => 988
    "pro_keywords_ar" => ""
    "pro_keywords_en" => ""
    "pro_meta_desc_ar" => ""
    "pro_meta_desc_en" => ""
    "created_at" => "2018-06-14 06:46:34"
    "updated_at" => "2018-11-30 20:06:58"
  ]
  #original: array:29 [
    "id" => 4
    "pro_special" => "2"
    "pro_active" => "2"
    "pro_main_cat_id" => 2
    "pro_sub_cat_id" => 2
    "pro_sub_sub_cat_id" => 3
    "pro_country_id" => 5
    "pro_city_id" => 7
    "pro_price" => 0.45
    "pro_discount_percentage" => 0
    "pro_after_discount" => 0.0
    "pro_image" => "upload/product/1529115234.Bruot.jpg"
    "pro_name_ar" => "خبز عربي 6 أرغفة"
    "pro_name_en" => "ARABISCHES BROT 6 STÜCK"
    "pro_desc_ar" => "<p>خبز عربي 6 أرغفة</p>\r\n"
    "pro_desc_en" => "<p>ARABISCHES BROT 6 STÜCK</p>\r\n"
    "pro_small_desc_ar" => "الوصف عربى"
    "pro_small_desc_en" => "الوصف المانى"
    "pro_slogen_ar" => "خبز-عربي-6-أرغفة"
    "pro_slogen_en" => "arabisches-brot-6-stck"
    "pro_view" => null
    "user_id" => 0
    "prod_count" => 988
    "pro_keywords_ar" => ""
    "pro_keywords_en" => ""
    "pro_meta_desc_ar" => ""
    "pro_meta_desc_en" => ""
    "created_at" => "2018-06-14 06:46:34"
    "updated_at" => "2018-11-30 20:06:58"
  ]
  #relations: []
  #hidden: []
  #visible: []
  #appends: []
  #fillable: []
  #guarded: array:1 [
    0 => "*"
  ]
  #dates: []
  #dateFormat: null
  #casts: []
  #touches: []
  #observables: []
  #with: []
  #morphClass: null
  +exists: true
  +wasRecentlyCreated: false

дд (Категория :: первая ());

App\Category {#907
  #connection: null
  #table: null
  #primaryKey: "id"
  #keyType: "int"
  #perPage: 15
  +incrementing: true
  +timestamps: true
  #attributes: array:11 [
    "id" => 2
    "cat_name_ar" => "        المواد الغذائية"
    "cat_name_en" => "   Lebensmittel"
    "cat_order" => "1"
    "cat_image" => "upload/category/maincat/1529112273.categ.jpg"
    "cat_restura" => null
    "cat_slogen_ar" => "المواد-الغذائية"
    "cat_slogen_en" => "lebensmittel"
    "status" => "1"
    "created_at" => "2018-06-10 09:26:24"
    "updated_at" => "2018-10-11 21:26:22"
  ]
  #original: array:11 [
    "id" => 2
    "cat_name_ar" => "        المواد الغذائية"
    "cat_name_en" => "   Lebensmittel"
    "cat_order" => "1"
    "cat_image" => "upload/category/maincat/1529112273.categ.jpg"
    "cat_restura" => null
    "cat_slogen_ar" => "المواد-الغذائية"
    "cat_slogen_en" => "lebensmittel"
    "status" => "1"
    "created_at" => "2018-06-10 09:26:24"
    "updated_at" => "2018-10-11 21:26:22"
  ]
  #relations: []
  #hidden: []
  #visible: []
  #appends: []
  #fillable: []
  #guarded: array:1 [
    0 => "*"
  ]
  #dates: []
  #dateFormat: null
  #casts: []
  #touches: []
  #observables: []
  #with: []
  #morphClass: null
  +exists: true
  +wasRecentlyCreated: false
}

Соответствующий маршрут в routes.php:

Route::auth();
Route::get('/', 'front\FrontController@index');

FrontController.php

<?php

namespace App\Http\Controllers\front;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Facades\Validator;
use App\Slider;
use App\HomeAdvert;
use App\Category;
use App\Product;
use App\Contact;
use App\Page;
use App\Country;
use App\City;
use App\Subcategory;

class FrontController extends Controller {

    public function index() {
        $sliders = Slider::orderBy('slider_order', 'asc')->get();
        $homeadvert = HomeAdvert::first();
        $homecategories = Category::where('status', '1')->orderBy('cat_order', 'desc')->with('products')->get();
        $homeproducts = $homecategories->map(function ($item) {
                                            return ($item->products()->limit(8))->get();
                                        });

        $homelatestproducts = Product::where('pro_active', 2)->orderBy('id', 'desc')->get()->take(8);


        $homecategorysearch = Category::where('status', '1')->orderBy('cat_order', 'desc')->get();
        $homecountrysearch = Country::orderBy('country_order', 'desc')->get();
        $pages = \App\Page::all();

        return view('frontend.layouts.index', compact('pages', 'homecategorysearch', 'homecountrysearch','homelatestproducts', 'homeproducts', 'sliders', 'homeadvert', 'homecategories'));
    }

}

Нет, ошибка возникает из-за того, что $ product обрабатывается как экземпляр Query Builder, что имеет смысл, в экземпляре построителя запросов нет метода mainCat (), но это должен быть экземпляр App \ Product, который есть mainCat (); метод. (Я отредактировал слово в ошибке, потому что оно написано неправильно, mainCategory (), а не mainCat ())

Omar Tarek 27.12.2018 12:38

Ошибка совершенно очевидно говорит о том, что вы не завершили свой запрос с помощью get(), first() или all() ... это все еще конструктор и нет результата. - Персональная рекомендация на стороне: вам следует использовать дополнительную таблицу для переводов полей, которая позволяет использовать дополнительные языки без необходимости изменения кода. Ваша текущая структура базы данных нарушает первую нормальную форму.

Namoshek 27.12.2018 12:43

что возвращается из get_class(App\Product::first()) в tinker?

Amade 27.12.2018 12:44

У вас есть данные в таблице товаров? Поскольку нет метода first (), он возвращает значение null. Пожалуйста, проверьте, есть ли у вас данные в таблице.

Manuel Eduardo Romero 27.12.2018 13:02

@Namoshek Если вы внимательно прочитаете, я специально использовал Product :: first (); в качестве моего запроса, что касается второй заметки о базе данных, я знаю, что меня наняли, когда приложение уже работает, так что прямо сейчас мы работаем над другими вещами, но спасибо за рекомендацию.

Omar Tarek 27.12.2018 13:15

@ManuelEduardoRomero Да, Product :: first (); возвращает полноценный экземпляр \ App \ Product, в таблице продуктов 854 продукта.

Omar Tarek 27.12.2018 13:16

@Amade Результат: "Приложение \ Продукт"

Omar Tarek 27.12.2018 13:18

Вы проверили, нет ли других неисправных вызовов (например, композитор представления, промежуточное ПО, ...)? А как насчет трассировки стека?

Namoshek 27.12.2018 13:27

@Namoshek Дело в том, что я ничего не менял, и вдруг все сломалось, и я не уверен, что вы имеете в виду под «трассировкой стека».

Omar Tarek 27.12.2018 13:31

Может это связано с какими-то глобальными масштабами? Что возвращается из: App\Product::first()->newQuery()? Думаю должен быть lluminate\Database\Eloquent\Builder. Это случайно не lluminate\Database\Query\Builder в вашем случае?

Amade 27.12.2018 13:34

Предлагаемые мной источники неудач не требуют изменений, а требуют лишь использования. Трассировка стека поможет найти местоположение, сообщив вам, из какого файла и номера строки возникла ошибка. На странице исключений Laravel по умолчанию обычно отображается трассировка стека. Если вы не знакомы с этим, проведите небольшое исследование. Это основы отладки.

Namoshek 27.12.2018 13:35

Нет, это Illuminate \ Database \ Eloquent \ Builder

Omar Tarek 27.12.2018 13:35

@Namoshek Я получал все свои ошибки от tinker, потому что представление лезвия не загружалось, потому что в нем было много "неопределенных переменных" из-за исходной проблемы, ни одна из назначенных мной переменных не загружалась, поэтому, когда я попытался dd ( Продукт :: первый ()); Например. СТРАНИЦА ЕЩЕ ЗАГРУЖЕНА, как будто dd () не используется; вообще..

Omar Tarek 27.12.2018 13:48

@Namoshek Итак, это еще более странно, когда я пытаюсь выполнить dd () или die () с контроллера, страница все еще пытается загрузиться, хотя я закомментировал строку return view () ... Она все еще пытается загрузить частичные элементы навигации и нижнего колонтитула, как будто dd () вообще не существует, он полностью игнорирует контроллер.

Omar Tarek 27.12.2018 13:55

Похоже, ваш маршрут выполняет другой метод контроллера. Используйте php artisan route:list, чтобы убедиться, что ваши маршруты правильно настроены. Может они кешируются? Очистить все кеши.

Namoshek 27.12.2018 13:58

@Namoshek Я уверен, что он загружает правильный контроллер и правильный метод, потому что, если я закомментирую этот маршрут, я получу 404.

Omar Tarek 27.12.2018 14:05

Тогда, пожалуйста, покажите нам весь ваш контроллер со всеми соответствующими методами.

Namoshek 27.12.2018 14:39

@Namoshek Готово.

Omar Tarek 27.12.2018 14:48

Я не вижу обращения к связи mainCategory в коде вашего контроллера. Но в качестве примечания, ваша линия Product::where('pro_active', 2)->orderBy('id', 'desc')->get()->take(8) будет страдать от плохой производительности, потому что take(8) выполняется в памяти. get() вернет коллекцию со всеми элементами из этой таблицы. Вы должны поместить take() перед get(), чтобы выполнить ограничение в базе данных.

Namoshek 27.12.2018 15:23

Соответствующее сопоставление запросов $homeproducts тоже выглядит странно ...

Namoshek 27.12.2018 15:24

@Namoshek Я ценю ваши заметки, но они не касаются основной проблемы, связанной с вызовом mainCategory, это был просто пример, поэтому его нет в этом контроллере, и я даже удалил все вызовы dd () из метода, ни один из них почему-то больше не работает ...

Omar Tarek 27.12.2018 16:06

Что ж, как мы можем помочь, если код и ошибка, которые вы нам показываете, не являются причиной реальной проблемы? Это не то, как работает отладка вопросов и ответов ...

Namoshek 27.12.2018 16:10

@Namoshek Хорошо, ты хочешь помочь? У вас есть маршрут и контроллер, прямо сейчас этот контроллер ни на что не отвечает. Как вы думаете, что мне делать? включает отношения работает, если я сделал dd (Product :: first () -> mainCategory)); rn в контроллере, он ничего не сделает, и представление будет возвращено.

Omar Tarek 27.12.2018 16:36
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
1
23
360
1

Ответы 1

first() и методы last() возвращают экземпляр класса, если его нет, они вернут ноль.

Вы можете сделать это, проверив возвращенные данные

$product = Product::first(); // or last() for eg.
if ($producto) { do something.... }

Или вы можете получить все продукты в каком-либо состоянии и проверить количество собранных результатов

$products::where('field','somthing')->get(); //or all()
if ($products->count()) { //or > 0 if you want
   do something...
}

Сначала проверьте, существуют ли данные в таблице продуктов.

Пожалуйста, попробуйте это и дайте мне знать, как это работает.

Мои запросы к базе данных работали так, как ожидалось, до некоторого момента, что-то вызвало критические изменения в моей среде разработки, в моей таблице продуктов есть 854 продукта, данные есть во всех таблицах.

Omar Tarek 27.12.2018 13:17

Не могли бы вы вставить сюда этот результат dd (Product :: first ());

Manuel Eduardo Romero 27.12.2018 13:40

Готово, добавил к самому вопросу.

Omar Tarek 27.12.2018 13:43

И dd (Product :: first () -> mainCategory); и, возможно, dd (Category :: first ()); чтобы увидеть структуру.

Manuel Eduardo Romero 27.12.2018 13:47

Товар хорошо выглядит. Возможно, в таблице категорий отсутствует какой-то идентификатор. Но я посмотрю, когда вы добавите другие дампы

Manuel Eduardo Romero 27.12.2018 13:49

dd (Product :: first () -> mainCategory); возвращает null, dd (Category :: first ()); возвращает экземпляр категории

Omar Tarek 27.12.2018 13:49

Добавлен dd (Category :: first ()) ;.

Omar Tarek 27.12.2018 13:51

Не могли бы вы попробовать это ... public function mainCategory() { return $this->belongsTo( 'App\Category', 'pro_main_cat_id', 'id' ); } первый параметр - это только имя класса в виде строки

Manuel Eduardo Romero 27.12.2018 20:26

Другие вопросы по теме