I'm trying to, from my controller, access a method in a model that is in another namespace and the only way I could do this was to make the method static. Is this the right way to do it, or is there any neater approach?
PagesController.php (controller):
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Helpers\ConnectedHost;
class PagesController extends Controller
{
/*
* REMOVED CODE HERE FOR READABILITY
* Below is where I instantiate the "connectedHost"-object
*/
$hosts[$hostKey] = new ConnectedHost($hostAttributes['ipv4'], $hostAttributes['mac']);
}
/* REMOVED CODE HERE FOR READABILITY AS WELL */
ConnectedHost.php (helper-file):
namespace App\Helpers;
class ConnectedHost
{
public $ipv4, $mac;
public function __construct($ipv4, $mac)
{
$this->ipv4 = $ipv4;
$this->mac = $mac;
// This is where I call the getName-function staticly,
$this->name = \App\Host::getName();
}
}
Host.php (model):
namespace App;
use Illuminate\Database\Eloquent\Model;
class Host extends Model
{
// The method below is declared static
public static function getName()
{
$name = 'wenzzzel';
return $name;
}
}
If you are directly accessing the method from model like
$data = \App\ModelName::methodName();
Then your method should be static.
if your method is not static you can access like,
$model = new \App\ModelName();
$data = $model->methodName();
Related
i have this trait which i want to use dependency injection
<?php
namespace App\Http\Controllers\Admin;
trait ControllerTrait{
public function index($this->model $payroll){
return $this->model->paginate(20);
}
}
the controller which uses this trait
namespace App\Http\Controllers\Admin;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Payroll;
class PayrollController extends Controller
{
use ControllerTrait;
public $model = "Payroll";
}
$model now is a string how to convert it to an object in calling index method of the trait
I don't believe dynamic type-hinting is possible, nor is it necessary in this instance.
I imagine this is what you're looking for.
namespace App\Http\Controllers\Admin;
trait ControllerTrait{
public function index() {
return ('\App\\'.$this->model)::paginate(20);
}
}
You can use "call_user_func" function which can call function in your model.
public $model = "Payroll";
call_user_func($model . "::index");
Hope this will help.
I think you can use it as a string in php
$controllerClassName = 'TODOS\CONTROLLERS\\' . ucfirst($this->_controller) . 'Controller';
which is a string and i used it to create instances
$controller = new $controllerClassName();
I have few classes which extends from the abstract class
And Class MenuController Extends from SiteAdminController
I need to call MenuController and receive authenticated user id
<?php
namespace App\Http\Controllers\SiteAdmin;
use App\Http\Categories;
use Illuminate\Http\Request;
use Gate;
use App\Category;
use App\Http\Controllers\MenuController;
use App\Site_categories;
use Auth;
class SiteAdminController extends \App\Http\SiteEntity implements Categories
{
protected $host;
public $user;
public function __construct()
{
parent::__construct();
$this->middleware('auth:admin');
}
protected function menu() {
return $data_nav['menu'] = MenuController::index('admin_categories');
}
Other one extends from SiteAdminCntroller
<?php
namespace App\Http\Controllers\SiteAdmin;
use Illuminate\Http\Request;
use Gate;
use Auth;
use App\Category;
class MenuController extends SiteAdminController
{
public $category_menu;
public $user_categories;
public $user;
public function __construct(Auth $auth)
{
//parent::__construct();
$this->user_categories=$this->CategoriesMenu();
$this->user=$auth::guard('admin')->user()->id;
dd($this->user);
//dd($this->user_categories);
}
I think the constructor in the MenuController run befor the middlware in SiteAdminController
Thats why I have such error
http://prntscr.com/hwfifx
Please Explaine what have I do to see result from me dd() function?
I was trying even to call parent::__construct but it not helping
You are correct that the the code in the constructor runs before the middleware: https://github.com/laravel/framework/issues/15072
The easiest way to get around this is to use the middleware method in the controller:
MenuController
public function __construct()
{
parent::__construct();
$this->middleware(function () {
$this->user_categories = $this->CategoriesMenu();
$this->user = auth()->guard('admin')->user()->id;
});
}
First of all check if the class see another class that must be extended with.
Then try below approach (it s just example):
class ConceptController extends \SiteAdminController {
public function __construct(SiteAdminController $siteAdmin) {
parent::__construct($siteAdmin);
}
}
Parent Class:
<?php
namespace App\Services;
class RequestVariables {
protected static $keys_tour;
public static function init() {
self::$keys_tour = array_flip(['tour_type', 'city_from']);
}
}
Child Class:
<?php
namespace App\Services;
class PreviousVersions extends RequestVariables {
public static function createVersion ($tour) {
dd(parent::$keys_tour);
}
}
When I call PreviousVersions::createVersion() from 1st controller:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Services\PreviousVersions;
use App\Tour;
class Tours2Controller extends Controller
{
public static function PreProcess($tour)
{
PreviousVersions::createVersion($tour);
}
}
it outputs what's expected:
array:2 [
"tour_type" => 0
"city_from" => 1 ]
but when I execute the same function in another controller:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Tour;
use App\Services\PreviousVersions;
class BookingController extends Controller {
public function booking($tour)
{
PreviousVersions::createVersion($tour);
}
}
it outputs 'null'
I can't see what's different between my controllers causing different results when calling the same method. Can somebody tell me why it outputs 'null' in the 2nd case?
If you need more information, please ask.
The $keys_tour property is being set inside the init() method of the RequestVariables class.
You can solve it by calling RequestVariables::init() inside the createVersions() method:
public static function createVersion ($tour)
{
RequestVariables::init();
}
Or using the parent keyword:
public static function createVersion ($tour)
{
parent::init();
}
Laravel 5.1
I'm trying to register a single model observer for every Model that extends my AbstractModel (who are extending Illuminate\Database\Eloquent\Model).
The problem is my GenericModelObserver can't listen to events fired by Models inheriting AbstractModel.
Let me show what I did so far.
A Service Provider was created and put on the last position of the providers array inside config/app.php
<?php
// app/Providers/ObserverServiceProvider.php
namespace App\Providers;
use App\Models\Quotation;
use App\Models\AbstractModel;
use App\Observers\QuotationObserver;
use App\Observers\GenericModelObserver;
use Illuminate\Support\ServiceProvider;
class ObserverServiceProvider extends ServiceProvider
{
public function boot()
{
AbstractModel::observe(GenericModelObserver::class);
Quotation::observe(QuotationObserver::class);
}
public function register()
{
}
}
Then I have my plain simple GenericModelObserver
<?php
// app/Observers/GenericModelObserver.php
namespace App\Observers;
use App\Models\AbstractModel;
class GenericModelObserver
{
public function saving(AbstractModel $model)
{
return $model->valid();
}
}
The Abstract Model
<?php
// app/Models/AbstractModel.php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class AbstractModel extends Model
{
// ...
}
My Quotation Model
<?php
// app/Models/Quotation.php
namespace App\Models;
class Quotation extends AbstractModel
{
// ...
}
When Quotation is saved, the GenericModelObserver can't listen to the saving event or any other event.
The same applies for other Models that don't have a specific Model Observer.
Is this the right strategy? I would not like to bind a observer to every model through the boot method.
Instead of extending model - write your own trait which will work as observer.
Below I wrote some basic trait:
<?php
namespace App\YourPackage\Traits;
use Illuminate\Database\Eloquent\Model;
trait Observable
{
public static function bootObservable()
{
static::updating(function (Model $model) {
dd('updating');
});
}
}
and use it by typing use Observable; in your model class.
Also for your learning take a note how traits is booting: You have to put boot[TraitClassName] method into trait, to boot it properly.
Never write boot method inside your trait, it's dangerous!
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\Observers\TeamObserver;
class Team extends Model
{
/**
* The "booting" method of the model.
*
* #return void
*/
protected static function boot()
{
parent::boot();
self::observe(TeamObserver::class);
}
}
Why not simply extend a parent class say BaseObserver
I have something similar in my caching system
<?php namespace App\Observers;
class BaseObserver {
public function saving($model)
{
//do your thing here that apply to all observers, like caching
}
}
Then in your Observers
<?php namespace App\Observers;
class Quotation extends BaseObserver{
//you can override any of the methods if you wish
}
Update the boot method in your AppServiceProvider to the following:
public function boot()
{
# Register all model observers
$filesInFolder = \File::files(app_path('/Observers'));
foreach($filesInFolder as $path) {
$observerClassName = pathinfo($path)['filename'];
$className = str_replace('Observer', '', $observerClassName);
$observerClassName = 'App\\Observers\\' . $observerClassName;
$className = 'App\\' . $className;
$className::observe($observerClassName);
}
}
Models should follow this format:
App\User
Observers should follow this format:
App\Observers\UserObserver
When models are in the 'models' folder:
Swap this $className = 'App\\' . $className; for this $className = 'App\\Models\\' . $className;
In your parent model you can do something like that
/**
* If true will attach the observers of the parent class
* #var bool
*/
protected $shouldAttachParentObservers = true;
public static function boot()
{
$instance = new static;
$instance->attachParentObservers();
parent::boot();
}
public function attachParentObservers() {
$parentClass = get_parent_class($this);
if(!empty($parentClass) && $this->shouldAttachParentObservers) {
$eventObservers = [];
foreach ($this->getObservableEvents() as $event) {
$eventObservers[$event] = ($this::$dispatcher->getListeners("eloquent.{$event}: {$parentClass}"));
foreach ($eventObservers[$event] as $observer) {
$eventName = "eloquent.{$event}: {$this::getClassName()}";
$this::$dispatcher->listen($eventName, $observer);
}
}
}
}
/**
* You may use different way to find the class name
*/
public static function getClassName() {
return static::class;
}
I have some trouble with namespace and use.
I get this error: "Trait 'Billing\BillingInterface' not found"
These are the files in my Laravel application:
Billing.php
namespace Billing\BillingInterface;
interface BillingInterface
{
public function charge($data);
public function subscribe($data);
public function cancel($data);
public function resume($data);
}
PaymentController.php
use Billing\BillingInterface;
class PaymentsController extends BaseController
{
use BillingInterface;
public function __construct(BillingPlatform $BillingProvider)
{
$this->BillingProvider = $BillingProvider;
}
}
How to i use use and namespace properly?
BillingInterface is an interface not a trait. Thus it can't find the non existent trait
Also you have an interface called BillingInterface in a namespace called Billing\BillingInterface, the fully qualified name of the interface is: \Billing\BillingInterface\BillingInterface
Perhaps you mean
use Billing\BillingInterface\BillingInterface;
// I am not sure what namespace BillingPlatform is in,
// just assuming it's in Billing.
use Billing\BillingPlatform;
class PaymentsController extends BaseController implements BillingInterface
{
public function __construct(BillingPlatform $BillingProvider)
{
$this->BillingProvider = $BillingProvider;
}
// Implement BillingInterface methods
}
Or to use it as a trait.
namespace Billing;
trait BillingTrait
{
public function charge($data) { /* ... */ }
public function subscribe($data) { /* ... */ }
public function cancel($data) { /* ... */ }
public function resume($data) { /* ... */ }
}
Again the modified PaymentsController, but with fully qualifies names.
class PaymentsController extends BaseController
{
// use the fully qualified name
use \Billing\BillingTrait;
// I am not sure what namespace BillingPlatform is in,
// just assuming it's in billing.
public function __construct(
\Billing\BillingPlatform $BillingProvider
) {
$this->BillingProvider = $BillingProvider;
}
}