I'm using Laravel 8 and I'm creating a custom Facade, but I cannot recall it with LogActivity::log($payload) but only with LogActivityFacade::log($payload).
Cannot see where is my fault...
app\Helpers\LogActivityFacade.php
<?php
namespace App\Helpers;
use Illuminate\Support\Facades\Facade;
class LogActivityFacade extends Facade
{
protected static function getFacadeAccessor()
{
return 'logactivity';
}
}
app\Helpers\LogActivityHelper.php
<?php
namespace App\Helpers;
use App\Repositories\LogActivityRepository;
class LogActivityHelper
{
public function log($payload)
{
$repository = new LogActivityRepository();
$repository->store($payload);
}
}
app\Providers\LogActivityServiceProvider.php
<?php
namespace App\Providers;
use Illuminate\Support\Facades\App;
use App\Helpers\LogActivityHelper;
use Illuminate\Support\ServiceProvider;
class LogActivityServiceProvider extends ServiceProvider
{
/**
* Register services.
*
* #return void
*/
public function register()
{
$this->app->bind('logactivity', function() {
return new LogActivityHelper();
});
}
/**
* Bootstrap services.
*
* #return void
*/
public function boot()
{
//
}
}
config/app.php
In providers array
[...]
App\Providers\LogActivityServiceProvider::class,
In alias array
'LogActivity' => App\Helpers\LogActivityFacade::class,
I tried also composer dump-autoload and php artisan config:clear, but I can access to the Facade (and it works...) only with LogActivityFacade::log() instead of LogActivity.
This is the expected behavior. Laravel doesn't create new classes for you it just proxies methods from the service class in the facade using the __call magic method. If you take a peek at, for example, the Auth or Route facade in the vendor directory you will see that they are named Auth and Route respectively not AuthFacade and RouteFacade. So just name your facade LogActivity. If you need to differentiate it from the service class you can use namespacing or just postfix the service class name with something as you have already done.
You can do this for easy access to the facades
namespace App\Facade;
use Illuminate\Support\Facades\Facade;
abstract class BaseFacade extends Facade
{
/**
* #return string
*/
public static function getFacadeAccessor()
{
return static::class ;
}
/**
* #param $class
*/
static function shouldProxyTo($class)
{
app()->singleton(self::getFacadeAccessor(),$class);
}
}
extend other facades
namespace App\Facade\Plugins;
use App\Facade\BaseFacade;
/**
* #method static convertPersianNumberToEnglish($number)
* #method static bool checkDataIsTrue(array $results = [])
* #method static string|null removeFileTypeName(string $string = null)
*/
class GlobalPluginsFacade extends BaseFacade
{
}
register in services provider
public function boot()
{
// global facades
GlobalPluginsFacade::shouldProxyTo(GlobalPluginsRepo::class);
}
And easy to use.
GlobalPluginsFacade::getFunction();
Related
i am using design patterns repository and i wrote every thing coorect but i have an error returns
Target [App\Repository\categoryRepositoryInterface] is not instantiable while building [App\Http\Controllers\CategoryController]. i dont know why although i wrote every thing correct please help
here is my code
my config/app
App\Providers\RepositoryServiceProvider::class,
and my categorycontroller
<?php
namespace App\Http\Controllers;
use App\Repository\categoryRepositoryInterface;
use Illuminate\Http\Request;
class CategoryController extends Controller
{
private categoryRepositoryInterface $categoryRepository;
public function __construct(categoryRepositoryInterface $categoryRepository)
{
$this->categoryRepository = $categoryRepository;
}
and my repositoryinterface
<?php
namespace App\Repository;
use Illuminate\Http\Request;
interface categoryRepositoryInterface
{
public function createCategory(Request $request);
public function validation(Request $request);
}
and my category repository
<?php
namespace App\Repository;
use App\Models\Category;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
class categoryRepository implements categoryRepositoryInterface{
public function validation(Request $request){
$validation = Validator::make($request->all(),[
'name' => 'required',
]);
if($validation->fails()){
return response()->json([
'status' => 400,
'errors' => $validation->errors(),
]);
}
}
public function createCategory(Request $request)
{
$category = new Category();
$category->name = $request->name;
$category->save();
}
}
and my servicerepositoryprovider
<?php
namespace App\Providers;
use App\Repository\CategoryRepository;
use App\Repository\CategoryRepositoryInterface;
use Illuminate\Support\ServiceProvider;
class RepositoryServiceProvider extends ServiceProvider
{
/**
* Register services.
*
* #return void
*/
public function register()
{
$this->app->bind(CategoryRepositoryInterface::class, CategoryRepository::class);
}
/**
* Bootstrap services.
*
* #return void
*/
public function boot()
{
//
}
}
You have typos in your RepositoryServiceProvier
use App\Repository\categoryRepository; //First alphabet should be lower case
use App\Repository\categoryRepositoryInterface; //First alphabet should be lower case
use Illuminate\Support\ServiceProvider;
class RepositoryServiceProvider extends ServiceProvider
{
/**
* Register services.
*
* #return void
*/
public function register()
{
//First alphabet should be lower case as per your class and interface names
$this->app->bind(categoryRepositoryInterface::class, categoryRepository::class);
}
/**
* Bootstrap services.
*
* #return void
*/
public function boot()
{
//
}
}
Would like to give you a piece of advice. When developing with Laravel it would be easier for you to follow Laravel's naming conventions - Laravel conventions overall. Following conventions will help you better understand examples on the internet as well.
Whatever you decide remember to follow them with consistency. In this particular case you are naming classes in camel case starting with small alphabet so when importing via use statements you need to stick to that.
I have service provider:
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class InvitationServiceProvider extends ServiceProvider
{
/**
* Register services.
*
* #return void
*/
public function register()
{
$this->app->bind('App\Service\InvitationServiceInterface', 'App\Service\InvitationService');
}
/**
* Bootstrap services.
*
* #return void
*/
public function boot()
{
//
}
}
Also there is an custom interface InvitationServiceInterface and InvitationService:
<?php
namespace App\Service;
class InvitationService implements InvitationServiceInterface
{
public function doAwesomeThing()
{
echo 'Do...';
}
}
Interface is:
<?php
namespace App\Service;
interface InvitationServiceInterface
{
public function doAwesomeThing();
}
These both files are place in path:
App\Service\InvitationServiceInterface
App\Service\InvitationService
So, I get an error:
Illuminate \ Contracts \ Container \ BindingResolutionException Target
[App\Service\InvitationServiceInterface] is not instantiable.
Using is:
use App\Service\InvitationServiceInterface;
use App\User;
use Illuminate\Http\Request;
class PassportController extends Controller
{
public function register(Request $request, InvitationServiceInterface $invitationService)
{
}
You can use the laravel service container in the constructor of a controller, i.e.:
class PassportController extends Controller
{
public function _construct(InvitationServiceInterface $invitationService)
{
$this->invitationService = $invitationService;
}
}
But not in a route controller function like you tried because here is the area of the route model binding so the service container is trying to instanciate a route model.
Probably service provider was cached.
Try to delete those two files:
Or run
php artisan config:clear
Or delete them derectry
rm bootstrap/cache/packages.php
rm bootstrap/cache/services.php
I'm trying to apply a sort of "repository-pattern" to a custom service.
What I'd like to do is to actually bind this library to my custom service provider to create an abstraction layer and, eventually, switch that library with another one in the future.
I'm trying to move the 'providers' and 'aliases' references from config/app.php to my service provider, but I get a Class 'GoogleMaps' not found error.
I've added App\Providers\GeoServiceProvider::class to config/app.php providers array and this is my relevant code:
GeoServiceProvider.php(my custom service provider)
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class GeoServiceProvider extends ServiceProvider
{
/** * Register services.
*
* #return void
*/
public function register()
{
$this->app->bind(\App\Interfaces\GeoInterface::class, \App\Services\GoogleGeoService::class);
$this->app->alias(\GoogleMaps\Facade\GoogleMapsFacade::class, 'GoogleMaps');
}
/**
* Bootstrap services.
*
* #return void
*/
public function boot()
{
}
}
GeoInterface.phpinterface defining standard methods
<?php
namespace App\Interfaces;
interface GeoInterface
{
public function geoCode();
}
GoogleGeoService.php(The actual library implementation)
<?php
namespace App\Services;
use App\Interfaces\GeoInterface;
class GoogleGeoService implements GeoInterface
{
public function geoCode()
{
$response = \GoogleMaps::load( 'geocoding' ) <--- HERE IS WHERE I GET THE ERROR
->setParamByKey( 'latlng', "45.41760620,11.90208370")
->setEndpoint( 'json' )
->get();
$response = json_decode($response, true);
return $response;
}
}
TestController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Interfaces\GeoInterface;
class TestController extends Controller
{
protected $geoService;
public function __construct(GeoInterface $geoService) {
$this->geoService = $geoService;
}
public function index() {
return $this->geoService->geoCode();
}
}
Thank you,
Alex
I'm getting the following error:
FatalErrorException in EloquentVehicle.php line 30: Call to a member
function groupBy() on null
I have the following code:
<?php
namespace App\Project\Frontend\Repo\Vehicle;
use Illuminate\Database\Eloquent\Model;
class EloquentVehicle implements VehicleInterface
{
protected $vehicle;
/**
* EloquentVehicle constructor.
*
* #param Model $vehicle
*/
public function __construct(
Model $vehicle
)
{
$this->$vehicle = $vehicle;
}
/**
* Fetch unique makes
*
* #return mixed
*/
public function fetchMakes()
{
return $this->vehicle->groupBy(array('make'))
->orderBy('make', 'asc')
->get();
}
}
I've checked Illuminate\Database\Eloquent\Model for the method which is obviously not there, but I don't know what I should be adding to my class so that I can use the groupBy method. The laravel docs say the method exists.
UPDATE: Apparently I can't typehint an abstract class. I don't know how else I should be going about using Eloquent to retrieve records. If it helps, below is the code I have for registering the classes to the service container
<?php
namespace App\Providers;
use App\Vehicle;
use App\Project\Frontend\Repo\Vehicle\EloquentVehicle;
use Illuminate\Support\ServiceProvider;
class RepoServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* #return void
*/
public function boot()
{
//
}
/**
* Register the application services.
*
* #return void
*/
public function register()
{
$this->app->bind('App\Project\Frontend\Repo\Vehicle\VehicleInterface', function($app)
{
return new EloquentVehicle(
new Vehicle
);
});
}
}
I just found my mistake and quite literally lay my face in my palms.
This
$this->$vehicle = $vehicle;
should be this
$this->vehicle = $vehicle;
I've set up a package in laravel 4 via the artisan workbench command. I created a facade class and followed this tutorial to come up with the following service provider, facade and root classes:
src/Spoolphiz/Infusionsoft/InfusionsoftServiceProvider.php:
namespace Spoolphiz\Infusionsoft;
use Illuminate\Support\ServiceProvider;
class InfusionsoftServiceProvider extends ServiceProvider {
protected $defer = false;
/**
* Bootstrap the application events.
*
* #return void
*/
public function boot()
{
$this->package('spoolphiz/infusionsoft');
}
/**
* Register the service provider.
*
* #return void
*/
public function register()
{
// Register 'infusionsoft' instance container to our Infusionsoft object
$this->app['infusionsoft'] = $this->app->share(function($app)
{
return new Spoolphiz\Infusionsoft\Infusionsoft;
});
}
/**
* Get the services provided by the provider.
*
* #return array
*/
public function provides()
{
return array();
}
}
src/Spoolphiz/Infusionsoft/Facades/Facade.php:
namespace Spoolphiz\Infusionsoft\Facades;
use Illuminate\Support\Facades\Facade;
class Infusionsoft extends Facade {
/**
* Get the registered name of the component.
*
* #return string
*/
protected static function getFacadeAccessor() { return 'infusionsoft'; }
}
Finally I've set up the underlying class thats to be connected to the facade at src/Spoolphiz/Infusionsoft/Infusionsoft.php:
namespace Spoolphiz\Infusionsoft;
//use Spoolphiz\Infusionsoft\iSDK;
/*
This is hackish and a un-laravel way to handle the requirement of \iSDK but unfortunately the xmlrpc3.0 lib doesn't want to correctly encode values when run with a namespace. Will try to resolve this later.
*/
require_once(__DIR__.'/isdk.php');
class Infusionsoft extends \iSDK {
protected $_app;
/**
* Init the sdk
*
*/
public function __construct( $connectionName )
{
$this->_app = parent::cfgCon($connectionName);
}
public function test()
{
dd('works');
}
}
I set up the service provider and the facade alias of Infusionsoft in app/config/config.php.
When I try running methods belonging to the extended iSDK class against an instance of Spoolphiz\Infusionsoft\Facade\Infusionsoft I get undefined method errors, such as the following:
Call to undefined method Spoolphiz\Infusionsoft\Facades\Infusionsoft::loadCon()
Why is this? The whole point of facades is to be able to call methods against its root class...
Looks like I was being stupid. I was developing this package in the laravel workbench. Once it was done I submitted it to packagist and set up a requirement for it in the same laravel app. Having the package installed in vendors directory and in the workbench caused some sort of conflict.
Lesson learned: make sure you dont have the same package in your workbench and in your application's vendors directory.