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.
Related
I am sorry if for someone the title of my question turns out to be very common, but the truth is that I have been trying for hours to obtain the expected result and I have not succeeded.
It happens, that I am developing a small package for Laravel, and I cannot perform a dependency injection in a method within a command that will contain the package.
Inside the directory structure of my package, I have the ServiceProvider
<?php
namespace Author\Package;
use Author\Package\Commands\BaseCommand;
use Author\Package\Contracts\MyInterface;
use Illuminate\Support\ServiceProvider;
class PackageServiceProvider extends ServiceProvider
{
/**
* The commands to be registered.
*
* #var array
*/
protected $commands = [
\Author\Package\Commands\ExampleCommand::class
];
/**
* Register services.
*
* #return void
*/
public function register()
{
if (! $this->app->configurationIsCached()) {
$this->mergeConfigFrom(__DIR__ . '/../config/package.php', 'package');
}
$this->app->bind(MyInterface::class, BaseCommand::class);
}
/**
* Bootstrap services.
*
* #return void
*/
public function boot()
{
if ($this->app->runningInConsole()) {
$this->publishes([
__DIR__ . '/../config/package.php' => config_path('package.php')
], 'package-config');
$this->configureCommands();
}
}
/**
* Register the package's custom Artisan commands.
*
* #return void
*/
public function configureCommands()
{
$this->commands($this->commands);
}
}
As you can see from the register method, I am creating a binding for when it calls the MyInterface interface, it returns the concrete BaseCommand class
public function register()
{
...
$this->app->bind(MyInterface::class, BaseCommand::class);
}
The structure of the ExampleCommand file is as follows:
<?php
namespace Author\Package\Commands;
use Author\Package\Contracts\MyInterface;
use Illuminate\Console\Command;
class ExampleCommand extends Command
{
/**
* The name and signature of the console command.
*
* #var string
*/
protected $signature = 'my:command';
/**
* The console command description.
*
* #var string
*/
protected $description = 'Command Description';
/**
* Execute the console command.
*
* #return void
*/
public function handle(MyInterface $interface)
{
// TODO
}
}
But when I run the command, I get the following error:
TypeError
Argument 1 passed to Author\Package\Commands\ExampleCommand::handle() must be an instance of Author\Package\Contracts\MyInterface, instance of Author\Package\Commands\BaseCommand given
I wonder why dependency injection is not working, in essence it should inject the concrete BaseCommand class into the handle method of the ExampleCommand class, but it isn't. I would appreciate any help you can give me.
Your BaseCommand must implement the interface that you have typehinted for that handle method. Dependency Injection happens before the method is called, so the container resolved your binding (as it is trying to pass an instance of BaseCommand to the method call, handle) but the binding does not return something that implements that contract so PHP won't allow that to be passed for that argument since it doesn't match the type of the argument in the signature (does not implement the contract).
In short: if you are going to bind a concrete to an abstract, make sure the concrete is actually of the type you are binding it to.
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();
I am trying to install kylekatarnls/business-day package into Laravel 6. The docs say to "First load the mixin in some global bootstrap place of your app:". Where do I put this code?
One option is to place this in the boot method of your AppServiceProvider.
<?php
namespace App\Providers;
use Cmixin\BusinessDay;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* #return void
*/
public function register()
{
}
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
$additional_holidays = [
// ...
];
BusinessDay::enable(\Illuminate\Support\Carbon::class, 'us-national', $additional_holidays);
}
}
Another option is to create your own Service Provider and place the code in the new service provider's boot method.
I have setting options which has controller and I need to get some of it's data on header and footer which need to be load globally.
How do I do that?
I've read some questions in this website but none of them helped me as I expected, or I didn't get those! either way I need your help to solve this issue of mine.
Thanks.
there are many ways to do that
but one of them that refer in laravel document is using boot
Sharing Data With All Views
Occasionally, you may need to share a piece of data with all views
that are rendered by your application. You may do so using the view
facade's share method. Typically, you should place calls to share
within a service provider's boot method. You are free to add them to
the AppServiceProvider or generate a separate service provider to
house them:
<?php
namespace App\Providers;
use Illuminate\Support\Facades\View;
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
View::share('key', 'value');
}
/**
* Register the service provider.
*
* #return void
*/
public function register()
{
//
}
}
you can share a variable inside boot method of AppServiceProvider.php
for example you have categories table and Category Model and you want to share it to all views
<?php
namespace App\Providers;
use Illuminate\Support\Facades\View;
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
$categories = Category::All();
View::share('categories', 'categories');
}
/**
* Register the service provider.
*
* #return void
*/
public function register()
{
//
}
}
but if you want to have header and footer for your site simply you can use master file and extend it to other views
document
Documentation on laravel.com is not sufficient. Can any one guide me through how to How To Create contracts in Laravel from scratch.
I need implementation of Contracts in Laravel. Right now, I'm using Laravel 5.4
Contract is just a fancy name for php interfaces. We have being using them all along and its not a new thing.
Contracts/Interfaces help us to maintain a loosely coupled code base. See the example from doc below.
<?php
namespace App\Orders;
class Repository
{
/**
* The cache instance.
*/
protected $cache;
/**
* Create a new repository instance.
*
* #param \SomePackage\Cache\Memcached $cache
* #return void
*/
public function __construct(\SomePackage\Cache\Memcached $cache)
{
$this->cache = $cache;
}
/**
* Retrieve an Order by ID.
*
* #param int $id
* #return Order
*/
public function find($id)
{
if ($this->cache->has($id)) {
//
}
}
}
Here when ever the Repository instantiate we should give a \SomePackage\Cache\Memcached instance in order for code to work. Hence our code is tightly coupled with \SomePackage\Cache\Memcached. Now look at below code.
<?php
namespace App\Orders;
use Illuminate\Contracts\Cache\Repository as Cache;
class Repository
{
/**
* The cache instance.
*/
protected $cache;
/**
* Create a new repository instance.
*
* #param Cache $cache
* #return void
*/
public function __construct(Cache $cache)
{
$this->cache = $cache;
}
}
Same thing but now we just need to provide some cache interface. And behind the scene you could have done something like this.
<?php
namespace App\Orders;
use Illuminate\Contracts\Cache\Repository as Cache;
class RedisCache implements Cache {
//
}
When above Repository instantiate, php will look at the Illuminate\Contracts\Cache\Repository and It has been implemented by RedisCache class.
I'm afraid Gayan's answer needs further elaboration to hit Rajan's question.
Yes Gayan is correct that creating a Contract class basically means creating a php interface.
Continuing the Cache example above, if we look into its source code (you can find it at this Github repo file), we can see something like this
<?php
namespace Illuminate\Contracts\Cache;
use Closure;
interface Repository
{
/**
* Determine if an item exists in the cache.
*
* #param string $key
* #return bool
*/
public function has($key);
/**
* Retrieve an item from the cache by key.
*
* #param string $key
* #param mixed $default
* #return mixed
*/
public function get($key, $default = null);
// the rest...
}
If we are using this interface in our laravel app, it is said to be a "Contract". It is declaring what methods/properties a class should have if it implements this interface. For example in our app...
<?php
namespace App\Whatever;
use Illuminate\Contracts\Cache\Repository;
class Foo implements Repository {
//
}
Then class Foo will need to have methods has and get in order to fulfil what has been stated in the Repository contract.