i am trying to write a package for laravel . i want to use facade and call some dynamic class with :: like this :
Zaya::test();
so , my structure is /packages/company/zaya and here is my composer for package :
"extra": {
"laravel": {
"providers": [
"Company\\Zaya\\ZayaServiceProvider"
],
"aliases": {
"Zaya": "Company\\Zaya\\ZayaFacade"
}
}
this is my fadace :
protected static function getFacadeAccessor()
{
return 'zaya';
}
and this is my service provider :
// Register the main class to use with the facade
$this->app->singleton('zaya', function () {
return new Zaya;
});
and finally this is my class :
<?php
namespace company\Zaya;
class Zaya
{
public function test()
{
return 123;
}
}
now in my controller when i call :
dd(Zaya::test());
i get this error :
"message": "Non-static method Company\\Zaya\\Zaya::test() should not be called statically",
You can use the app helper to resolve the class:
class MyFacade
{
public static function __callStatic($method, $arguments)
{
$class = app(MyClass::class);
return $class->$method(...$arguments);
}
}
To use it:
MyFacade::foo();
MyFacade::bar();
MyFacade::baz();
// or in your case
Zaya::test();
Related
I laravel 9 app I use EmailingServiceProvider with conditional binding of EmailingService depending
on configuration :
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class EmailingServiceProvider extends ServiceProvider
{
public function register()
{
$emailingSupport = config('app.emailing_support');
if($emailingSupport === 'MailerLiteApi') {
$this->app->bind('App\Library\Services\EmailingServiceInterface', 'App\Library\Services\EmailingService');
}
}
}
class EmailingService is called in controller ok, except cases when I want to comment binding code above :
// $this->app->bind
I tried to use example at https://www.php.net/manual/en/reflectionclass.isinstantiable.php as :
...
use App\Library\Services\EmailingServiceInterface;
class AuthorController extends Controller
{
private AuthorMethodsServiceInterface $authorMethodsService;
private EmailingServiceInterface $emailingService;
public function __construct(AuthorMethodsServiceInterface $authorMethodsService /*, EmailingServiceInterface $emailingService*/ )
{
parent::__construct();
$this->authorMethodsService = $authorMethodsService;
// $this->emailingService = $emailingService; // I had to comment this and declarations above
}
// I expected that $reflectionClass->isInstantiable() would have false value below
$reflectionClass = new \ReflectionClass('EmailingService'); // Line points at this line
if $reflectionClass->isInstantiable()) {
$this->emailingService = new EmailingService();
$assignedAuthor = $this->emailingService->method();
But I ggot error":
"message": "Class \"EmailingService\" does not exist",
"exception": "ReflectionException",
How that can be done ?
MODIFIED BLOCK :
That does not work. With lines :
use App\Library\Services\EmailingServiceInterface;
...
$yourService=new EmailingService(); // Error pointing at this line
if ($author instanceof \Illuminate\Http\JsonResponse and $yourService instanceof EmailingServiceInterface) {
...
I got error:
"message": "Class \"App\\Http\\Controllers\\EmailingService\" not found",
"exception": "Error",
?
Thanks!
you can use instanceof
use App\Library\Services\EmailingServiceInterface;
if ($yourService instanceof EmailingServiceInterface) {
//
}
I am new to laravel and I have two of these classes
namespace Kharota\Libraries;
class Input {
public function input($input)
{
echo "inèut";
}
}
and Form Class
namespace Kharota\Libraries;
class Forms
{
public static function form($params, $callback)
{
if(is_callable( $callback)) {
call_user_func( $callback);
}
}
}
I am trying to call like this
use Kharota\Libraries\Forms;
use Kharota\Libraries\Input;
...
Forms::form( [], function(Input $input) {
$input->input( [] );
});
But I am getting error
(1/1) ErrorException
Argument 1 passed to Illuminate\Support\ServiceProvider::{closure}() must be an instance of Kharota\Libraries\Input, none given
How I can fix it?
You should write use Kharota\Lib... between <?php and class OtherClass.
I am trying to extend an existing plugin component and I
need to add a function but use plugins methods.
Here what I have:
<?php namespace Bbrand\Shop\Components;
use Cms\Classes\ComponentBase;
use Jiri\JKShop\Components\Basket;
class Shopextend extends ComponentBase
{
public function componentDetails()
{
return [
'name' => 'shopextend Component',
'description' => 'No description provided yet...'
];
}
public function defineProperties()
{
return [];
}
public function onBasket(){
$data = [];
$data["basket"] = Basket::getSessionBasket();
$data["jkshopSetting"] = \Jiri\JKShop\Models\Settings::instance();
return [
$this->property("idElementWrapperBasketComponent") => $this->renderPartial('#basket-0', $data)
];
}
}
But I'm getting an error
"Non-static method Jiri\JKShop\Components\Basket::getSessionBasket()
should not be called statically" on line 30 of
/Applications/MAMP/htdocs/fidgycube.co/plugins/bbrand/shop/components/Shopextend.php
Any help!?
thanks
You need to add component first.
<?php namespace Bbrand\Shop\Components;
class Shopextend extends ComponentBase
{
public function init()
{
// Add component
$this->addComponent('\Jiri\JKShop\Components\Basket', 'basket', []);
}
}
I'm using Slim Framework 3 to create an API. The app structure is: MVCP (Model, View, Controller, Providers).
Is it possible to have Slim Dependency Inject all my classes?
I'm using composer to autoload all my dependencies.
My directory structure looks like this:
/app
- controllers/
- Models/
- services/
index.php
/vendor
composer.json
Here's my composer.json file.
{
"require": {
"slim/slim": "^3.3",
"monolog/monolog": "^1.19"
},
"autoload" : {
"psr-4" : {
"Controllers\\" : "app/controllers/",
"Services\\" : "app/services/",
"Models\\" : "app/models/"
}
}
}
Here's my index.php file. Again, the dependencies are being auto injected by composer
<?php
use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;
require '../vendor/autoload.php';
$container = new \Slim\Container;
$app = new \Slim\App($container);
$app->get('/test/{name}', '\Controllers\PeopleController:getEveryone');
$app->run();
My controller looks like this
<?php #controllers/PeopleController.php
namespace Controllers;
use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;
class PeopleController
{
protected $peopleService;
protected $ci;
protected $request;
protected $response;
public function __construct(Container $ci, PeopleService $peopleService)
{
$this->peopleService = $peopleService;
$this->ci = $ci;
}
public function getEveryone($request, $response)
{
die($request->getAttribute('name'));
return $this->peopleService->getAllPeoples();
}
}
My PeopleService file looks like this:
<?php
namespace Services;
use Model\PeopleModel;
use Model\AddressModel;
use Model\AutoModel;
class PeopleService
{
protected $peopleModel;
protected $autoModel;
protected $addressModel;
public function __construct(PeopleModel $peopleModel, AddressModel $addressModel, AutoModel $autoModel)
{
$this->addressModel = $addressModel;
$this->autoModel = $autoModel;
$this->peopleModel = $peopleModel;
}
public function getAllPeopleInfo()
{
$address = $this->addressModel->getAddress();
$auto = $this->autoModel->getAutoMake();
$person = $this->peopleModel->getPeople();
return [
$person[1], $address[1], $auto[1]
];
}
}
Models/AddressModels.php
<?php
namespace Model;
class AddressModel
{
public function __construct()
{
// do stuff
}
public function getAddress()
{
return [
1 => '123 Maple Street',
];
}
}
Models/AutoModel.php
namespace Model;
class AutoModel
{
public function __construct()
{
// do stuff
}
public function getAutoMake()
{
return [
1 => 'Honda'
];
}
}
Models/PeopleModel.php
<?php
namespace Model;
class PeopleModel
{
public function __construct()
{
// do stuff
}
public function getPeople()
{
return [
1 => 'Bob'
];
}
}
ERROR
I'm getting the following error now:
PHP Catchable fatal error: Argument 2 passed to Controllers\PeopleController::__construct() must be an instance of Services\PeopleService, none given, called in /var/www/vendor/slim/slim/Slim/CallableResolver.php on line 64 and defined in /var/www/app/controllers/PeopleController.php on line 21
THE QUESTION
How do I dependency inject all my classes? Is there a way to automagically tell Slim's DI Container to do it?
When you reference a class in the route callable Slim will ask the DIC for it. If the DIC doesn't have a registration for that class name, then it will instantiate the class itself, passing the container as the only argument to the class.
Hence, to inject the correct dependencies for your controller, you just have to create your own DIC factory:
$container = $app->getContainer();
$container['\Controllers\PeopleController'] = function ($c) {
$peopleService = $c->get('\Services\PeopleService');
return new Controllers\PeopleController($c, $peopleService);
};
Of course, you now need a DIC factory for the PeopleService:
$container['\Services\PeopleService'] = function ($c) {
$peopleModel = new Models\PeopleModel;
$addressModel = new Models\AddressModel;
$autoModel = new Models\AutoModel;
return new Services\PeopleService($peopleModel, $addressModel, $autoModel);
};
(If PeopleModel, AddressModel, or AutoModel had dependencies, then you would create DIC factories for those too.)
Synopsis
I am building a system with at least two levels of Authentication and both have separate User models and tables in the database. A quick search on google and the only solution thus far is with a MultiAuth package that shoehorns multiple drivers on Auth.
My goal
I am attempting to remove Auth which is fairly straight-forward. But I would like CustomerAuth and AdminAuth using a separate config file as per config/customerauth.php and config\adminauth.php
Solution
I'm assuming you have a package available to work on. My vendor namespace in this example will simply be: Example - all code snippets can be found following the instructions.
I copied config/auth.php to config/customerauth.php and amended the settings accordingly.
I edited the config/app.php and replaced the Illuminate\Auth\AuthServiceProvider with Example\Auth\CustomerAuthServiceProvider.
I edited the config/app.php and replaced the Auth alias with:
'CustomerAuth' => 'Example\Support\Facades\CustomerAuth',
I then implemented the code within the package for example vendor/example/src/. I started with the ServiceProvider: Example/Auth/CustomerAuthServiceProvider.php
<?php namespace Example\Auth;
use Illuminate\Auth\AuthServiceProvider;
use Example\Auth\CustomerAuthManager;
use Example\Auth\SiteGuard;
class CustomerAuthServiceProvider extends AuthServiceProvider
{
public function register()
{
$this->app->alias('customerauth', 'Example\Auth\CustomerAuthManager');
$this->app->alias('customerauth.driver', 'Example\Auth\SiteGuard');
$this->app->alias('customerauth.driver', 'Example\Contracts\Auth\SiteGuard');
parent::register();
}
protected function registerAuthenticator()
{
$this->app->singleton('customerauth', function ($app) {
$app['customerauth.loaded'] = true;
return new CustomerAuthManager($app);
});
$this->app->singleton('customerauth.driver', function ($app) {
return $app['customerauth']->driver();
});
}
protected function registerUserResolver()
{
$this->app->bind('Illuminate\Contracts\Auth\Authenticatable', function ($app) {
return $app['customerauth']->user();
});
}
protected function registerRequestRebindHandler()
{
$this->app->rebinding('request', function ($app, $request) {
$request->setUserResolver(function() use ($app) {
return $app['customerauth']->user();
});
});
}
}
Then I implemented: Example/Auth/CustomerAuthManager.php
<?php namespace Example\Auth;
use Illuminate\Auth\AuthManager;
use Illuminate\Auth\EloquentUserProvider;
use Example\Auth\SiteGuard as Guard;
class CustomerAuthManager extends AuthManager
{
protected function callCustomCreator($driver)
{
$custom = parent::callCustomCreator($driver);
if ($custom instanceof Guard) return $custom;
return new Guard($custom, $this->app['session.store']);
}
public function createDatabaseDriver()
{
$provider = $this->createDatabaseProvider();
return new Guard($provider, $this->app['session.store']);
}
protected function createDatabaseProvider()
{
$connection = $this->app['db']->connection();
$table = $this->app['config']['customerauth.table'];
return new DatabaseUserProvider($connection, $this->app['hash'], $table);
}
public function createEloquentDriver()
{
$provider = $this->createEloquentProvider();
return new Guard($provider, $this->app['session.store']);
}
protected function createEloquentProvider()
{
$model = $this->app['config']['customerauth.model'];
return new EloquentUserProvider($this->app['hash'], $model);
}
public function getDefaultDriver()
{
return $this->app['config']['customerauth.driver'];
}
public function setDefaultDriver($name)
{
$this->app['config']['customerauth.driver'] = $name;
}
}
I then implemented Example/Auth/SiteGuard.php (note the methods implemented have an additional site_ defined, this should be different for other Auth drivers):
<?php namespace Example\Auth;
use Illuminate\Auth\Guard;
class SiteGuard extends Guard
{
public function getName()
{
return 'login_site_'.md5(get_class($this));
}
public function getRecallerName()
{
return 'remember_site_'.md5(get_class($this));
}
}
I then implemented Example/Contracts/Auth/SiteGuard.php
use Illuminate\Contracts\Auth\Guard;
interface SiteGuard extends Guard {}
Finally I implemented the Facade; Example/Support/Facades/Auth/CustomerAuth.php
<?php namespace Example\Support\Facades;
class CustomerAuth extends Facade
{
protected static function getFacadeAccessor()
{
return 'customerauth';
}
}
A quick update, when trying to use these custom auth drivers with phpunit you may get the following error:
Driver [CustomerAuth] not supported.
You also need to implement this, the easiest solution is override the be method and also creating a trait similar to it:
<?php namespace Example\Vendor\Testing;
use Illuminate\Contracts\Auth\Authenticatable as UserContract;
trait ApplicationTrait
{
public function be(UserContract $user, $driver = null)
{
$this->app['customerauth']->driver($driver)->setUser($user);
}
}