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).
Related
I have a Base model that I used to extend in all other Models. I created an observer for it called BaseObserver and registered it at boot method of EventServiceProvider. I have a creating event and would like to put my logic there every time I create a new other Model.
The problem is that the creating method in BaseObserver is not being called. But, when I created a closure for creating in Base model, it worked. What seems to be the problem here?
Base.php
namespace App\Models;
use Jenssegers\Mongodb\Eloquent\Model;
use Jenssegers\Mongodb\Eloquent\SoftDeletes;
class Base extends Model
{
use SoftDeletes;
protected $dates = ['deleted_at'];
// This closure will work but If I commented this out, BaseObserver's creating method won't work
protected static function booted()
{
static::creating(function ($base) {
dd('hellp from base model');
});
}
}
BaseObserver.php
namespace App\Observers;
use App\Models\Base;
class BaseObserver
{
public function creating(Base $base)
{
dd('hello from base obserer');
$base->created_by = auth()->user()?->_id;
}
public function updating(Base $base)
{
dd('hello from base obserer');
$base->updated_by = auth()->user()?->_id;
}
}
EventServiceProvider.php
namespace App\Providers;
use App\Models\Base;
use App\Observers\BaseObserver;
use Illuminate\Auth\Events\Registered;
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
class EventServiceProvider extends ServiceProvider
{
protected $listen = [
Registered::class => [
SendEmailVerificationNotification::class,
],
];
public function boot()
{
Base::observe(BaseObserver::class);
}
public function shouldDiscoverEvents()
{
return false;
}
}
Team.php
namespace App\Models;
use App\Models\Base;
use Illuminate\Database\Eloquent\Factories\HasFactory;
class Team extends Base
{
use HasFactory;
protected $fillable = [
'name',
'leader_id',
'member_ids',
];
}
Result
it has to work
class Base extends Model
{
protected static function booted()
{
static::observe(BaseObserver::class);
}
}
I am creating a command and a helper function in laravel.
In app/Helper/Function.php
<?php
namespace App\Helper;
class Function
{
static public function testCommand()
{
return "success";
}
}
In Console/Commands/TestCommand.php
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class TestCommand extends Command
{
protected $signature = 'test:command';
protected $description = 'Test Command';
public function __construct()
{
parent::__construct();
}
public function handle()
{
// call the helper's testCommand function here
}
}
Now I want to call the testCommand() function on function handle() to process
And when I run: : php artisan test:command then it will get the result of the function :testCommand() . Thanks
I found the solution:
<?php
namespace App\Console\Commands;
use App\Helper\Function;
use Illuminate\Console\Command;
class TestCommand extends Command
{
protected $signature = 'test:command';
protected $description = 'Test Command';
public function __construct()
{
parent::__construct();
}
public function handle()
{
$test = Function:: testCommand();
return $test;
}
}
I can't get my repository working, when i'm just trying the get the entire list of documents it returns nothing
Here's my DocumentRepository
<?php
namespace App\Repositories\Document;
interface DocumentRepository
{
public function getall();
public function getById($id);
public function create(array $attributes);
public function update ($id, array $attributes);
public function delete ($id);
}
Here's the functions
<?php
namespace App\Repositories\Document;
class EloquentDocument implements DocumentRepository
{
private $model;
public function __construct(Document $model)
{
$this->model = $model;
}
public function getall()
{
return $this->model->all();
}
public function getById($id)
{
return $this->findById($id);
}
public function create(array $attributes)
{
return $this->model->create($attributes);
}
public function delete($id)
{
$this->getById($id)->delete();
return true;
}
public function update($id array $attributes)
{
$document = $this->model->findOrFail($id);
$document->update($attribute);
return $document;
}
}
and here's the controller
<?php
namespace App\Http\Controllers;
use App\Repositories\Document;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
class DocumentController extends Controller
{
/**
* #var DocumentRepository
*/
private $document;
/**
* TodoController constructor.
*/
public function __construct(DocumentController $document)
{
$this->document = $document;
}
public function getalldocuments()
{
return $this->document->getAll();
}
}
For your information there's two rows of data in my Documents table/model so i just want to get both of them by just simply returning but in my case it simply returns nothing.
Here's the route
Route::get('/documents', 'DocumentController#getalldocuments');
here's the registration part insite AppServiceProviders.php
public function register()
{
$this->app->singleton(DocumentRepository::class, EloquentDocument::class);
}
You are type-hinting DocumentController instead of your actual repository.
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use App\Repositories\Document\DocumentRepository;
class DocumentController extends Controller
{
/**
* #var DocumentRepository
*/
private $document;
public function __construct(DocumentRepository $document)
{
$this->document = $document;
}
public function getalldocuments()
{
return $this->document->getAll();
}
}
Now, assuming you have properly binded the interface to resolve to your document repository implemented, this should work.
For more information on how to bind interfaces to implementation, read this: https://laravel.com/docs/5.7/container#binding-interfaces-to-implementations
Edit: You have some syntax issues in your repository's interface. You are missing function:
<?php
namespace App\Repositories\Document;
interface DocumentRepository
{
public function getall();
public function getById($id);
public function create(array $attributes);
public function update($id, array $attributes);
public function delete($id);
}
Edit 2: Your binding is correct. However, I noticed that you are not binding your App\Document model to the implementation correctly.
<?php
namespace App\Repositories\Document;
use App\Document;
class EloquentDocument implements DocumentRepository
{
private $model;
public function __construct(Document $model)
{
$this->model = $model;
}
//
//
//
}
You need to add the correct use statement at the top. Assuming your document model resides in App\Document this should work.
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.
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');
}
}