Magento 2 Error - Model collection resource name is not defined - magento

I'm going through Magento 2 tutorials and I'm having trouble getting a collection from my custom model's factory after calling the create() method. It throws an error saying the "Model collection resource name is not defined". I've already cleared /var/generation and recompiled the di.
Company/Module/Model/Vendor.php
namespace Company\Module\Model;
class Vendor extends \Magento\Framework\Model\AbstractModel {
protected function _constructor() {
$this->_init('Company\Module\Model\Resource\Vendor');
}
}
Company/Module/Model/Resource/Vendor.php
namespace Company\Module\Model\Resource;
class Vendor extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb
{
protected function _construct()
{
$this->_init(
'company_vendor',
'vendor_id'
);
}
}
Company/Module/Model/Resource/Vendor/Collection.php
namespace Company\Module\Model\Resource\Vendor;
class Collection extends \Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection
{
protected function _construct()
{
$this->_init(
'Company\Module\Model\Vendor',
'Company\Module\Model\Resource\Vendor'
);
}
}
Company/Module/Block/VendorList.php
namespace Company\Module\Block;
class VendorList extends \Magento\Framework\View\Element\Template {
protected $vendorFactory;
public function __construct(\Magento\Framework\View\Element\Template\Context $context,
\Company\Module\Model\VendorFactory $vendorFactory,
array $data = [])
{
parent::__construct($context, $data);
$this->vendorFactory = $vendorFactory;
}
public function getVendors() {
return $this->vendorFactory->create()->getCollection()->getItems(); //fails on getCollection()
}
This is the error I get:
1 exception(s):
Exception #0 (Magento\Framework\Exception\LocalizedException): Model collection resource name is not defined.

You need to do following change.
Company/Module/Model/Vendor.php
namespace Company\Module\Model;
class Vendor extends \Magento\Framework\Model\AbstractModel {
protected function _constructor() {
$this->_init('Company\Module\Model\ResourceModel\Vendor');
}
}
Company/Module/Model/ResourceModel/Vendor.php
namespace Company\Module\Model\ResourceModel;
class Vendor extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb
{
protected function _construct()
{
$this->_init('company_vendor','vendor_id');
}
}
Company/Module/Model/ResourceModel/Vendor/Collection.php
namespace Company\Module\Model\ResourceModel\Vendor;
class Collection extends \Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection
{
public function _construct()
{
$this->_init('Company\Module\Model\Vendor','Company\Module\Model\ResourceModel\Vendor'
);
}
}

The issue was I had _constructor() instead of _construct()
namespace Company\Module\Model;
class Vendor extends \Magento\Framework\Model\AbstractModel {
protected function _construct() {
$this->_init('Company\Module\Model\Resource\Vendor');
}
}

Related

Unable to find observer in Laravel

I tried to register my ObserverHelper in the AppServiceProvider as below, but I am getting the following error.
Unable to find observer: App\Helpers\App\Observers\FileLogObserver
AppServiceProvider.php
use Illuminate\Support\ServiceProvider;
use App\Helpers\ObserverHelper;
class AppServiceProvider extends ServiceProvider
{
public function register()
{
}
public function boot()
{
ObserverHelper::register();
}
}
ObserverHelper.php
namespace App\Helpers;
class ObserverHelper
{
protected static $observers = [
'App\Models\FileLogs' => App\Observers\FileLogObserver::class,
];
public static function register()
{
foreach (self::$observers as $model => $observer) {
$model::observe($observer);
}
}
}
Try adding a \ (backslash that references the global namespace) in front of the App\Observers\FileLogObserver::class, or import that class.
With backslash (reference global namespace):
<?php
namespace App\Helpers;
class ObserverHelper
{
protected static $observers = [
'App\Models\FileLogs' => \App\Observers\FileLogObserver::class,
];
public static function register()
{
foreach(self::$observers as $model => $observer) {
$model::observe($observer);
}
}
}
or with import:
<?php
namespace App\Helpers;
use App\Observers\FileLogObserver;
class ObserverHelper
{
protected static $observers = [
'App\Models\FileLogs' => FileLogObserver::class,
];
public static function register()
{
foreach(self::$observers as $model => $observer) {
$model::observe($observer);
}
}
}
Note: Even though your code is a valid solution, consider creating a separate provider for defining observers (ObserverServiceProvider for example).

Override Eloquent Relation Create Method

I want to override create method, but with relation, it didn't touch the create method.
There are Two Models:
class User extends Model
{
public function user_detail()
{
return $this->hasOne(UserDetail::class);
}
}
class UserDetail extends Model
{
public static function create(array $attributes = [])
{
//I was trying to do something like
/*
if(isset($attributes['last_name']) && isset($attributes['first_name']))
{
$attributes['full_name']=$attributes['first_name'].' '.$attributes['last_name'];
}
unset($attributes['first_name'],$attributes['last_name']);
*/
Log::debug('create:',$attributes);
$model = static::query()->create($attributes);
return $model;
}
}
When I use UserDetail::create($validated), and there is a log in laravel.log, so I know the code touched my custom create method.
But if I use
$user = User::create($validated);
$user->user_detail()->create($validated);
There is no log in laravel.log, which means laravel didn't touch the create method, then how I supposed to do to override create method under this circumstance?(I'm using laravel 5.7)
Thank you #Jonas Staudenmeir, after I read the documentation, here is my solution.
If the $attributes are not in protected $fillable array, then I do it in the __construct method.
class UserDetail extends Model
{
protected $fillable=['full_name','updated_ip','created_ip'];
public function __construct(array $attributes = [])
{
if (isset($attributes['first_name']) && isset($attributes['last_name'])) {
$attributes['full_name'] = $attributes['first_name'].' '.$attributes['last_name'];
}
parent::__construct($attributes);
}
}
Otherwise, I do it in Observer.
namespace App\Observers;
use App\Models\UserDetail;
class UserDetailObserver
{
public function creating(UserDetail $userDetail)
{
$userDetail->created_ip = request()->ip();
}
public function updating(UserDetail $userDetail)
{
$userDetail->updated_ip = request()->ip();
}
}
Register Observer in AppServiceProvider.
namespace App\Providers;
use App\Models\UserDetail;
use App\Observers\UserDetailObserver;
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
UserDetail::observe(UserDetailObserver::class);
}
}
I choose Observer instead of Event&Listener is for easy maintenance.

Call to undefined relationship on model

We have the following class using $with:
class CargaHorasEmpleado extends Model
{
protected $table = "empleados_horas";
protected $with = ["tipoTarea", "proyecto", "empleado", "empleadoQueHizoLaCarga"];
public function tipoTarea()
{
return $this->belongsTo('App\TipoTarea', 'id_tipo_tarea', 'id')->withTrashed();
}
public function empleado()
{
return $this->belongsTo('App\Empleado', 'id_empleado', 'id')->withTrashed();
}
public function empleadoQueHizoLaCarga()
{
return $this->belongsTo('App\Empleado', 'id_empleado_cargo_hs', 'id')->withTrashed();
}
public function proyecto()
{
return $this->belongsTo('App\Proyecto', 'id_proyecto', 'id')->withTrashed();
}
}
This is the class TipoTarea
namespace App;
use Illuminate\Database\Eloquent\Model;
class TipoTarea extends Model
{
protected $table = 'tipos_tareas';
public $timestamps = false;
protected $fillable = [
'titulo', 'descripcion'
];
}
Thep page throws the error: "Call to undefined relationship [tipoTarea] on model [App\CargaHorasEmpleado]". That's the only relationship that's not working. The others are fine. What's wrong?
Well, isn't the relationship called "tipoTarea"? You wrote "tiposTarea"
The problem was that my class "TipoTarea" didn't use softdeletes. So the error was in using the "WithTrashed" method. The correct way is:
public function tipoTarea()
{
return $this->belongsTo('App\TipoTarea', 'id_tipo_tarea', 'id');
}

How can I solve Target [App\Repositories\NewsRepository] is not instantiable while building [App\Http\Controllers\Member\NewsController].?

My controller like this :
...
use App\Repositories\NewsRepository;
class NewsController extends Controller
{
protected $repository;
public function __construct(NewsRepository $repository)
{
$this->repository = $repository;
}
public function store(NewsCreateRequest $request)
{
...
$news = $this->repository->create($input);
...
}
}
My interface like this :
namespace App\Repositories;
use Prettus\Repository\Contracts\RepositoryInterface;
interface NewsRepository extends RepositoryInterface
{
//
}
My class like this :
...
use App\Repositories\NewsRepository;
class NewsRepositoryEloquent extends BaseRepository implements NewsRepository
{
public function model()
{
return News::class;
}
public function boot()
{
$this->pushCriteria(app(RequestCriteria::class));
}
}
My repository service provider like this :
...
class RepositoryServiceProvider extends ServiceProvider
{
...
public function register()
{
...
$this->app->bind(\App\Repositories\NewsRepository::class, \App\Repositories\NewsRepositoryEloquent::class);
}
}
If the method store on the controller executed, there exist error :
(1/1) BindingResolutionException Target
[App\Repositories\NewsRepository] is not instantiable while building
[App\Http\Controllers\Member\NewsRepository].
How can I solve the error?
You have to add constructor to your repository and call parent constructor for setup model like this:
public function __construct(Permission $model)
{
parent::__construct($model);
}

Laravel - check if the Eloquent object is found inside model

In my controller I would like to have this:
class TodoController extends Controller {
public function getDone($todoId)
{
Todo::find($todoId)->markAsDone();
}
}
model I have:
class Todo extends Eloquent {
public function markAsDone()
{
if (???) {
$this->is_done = 1;
$this->save();
}
}
}
How can I check if the model is found and is present in $this?
In your case, checking the existence of ToDo object can only be done in controller. Because in your current code Todo::find($todoId)->markAsDone(); if the $todoId is invalid, you will be have BIG error, trying to get property of non-object. So its better to do this.
class TodoController extends Controller {
public function getDone($todoId)
{
$todo = Todo::find($todoId);
if ($todo) {
$todo->markAsDone();
}
}
}
And in your model
class Todo extends Eloquent {
public function markAsDone()
{
$this->is_done = 1;
$this->save();
}
}

Resources