I need to handle different types of DB depending on the client.
I created a Facade called MyDBFacade where I can call my own functions.
For example:
MyDBFacade::createDBUser("MyUser"); // will create a DB user whatever I'm using Postgres or SQL Server
Is there a possibility to extends the framework Facade DB:: in a way I could add my own functions and then call DB::createUser("MyUser") ?
Any clue or idea would be appreciate.
Thanks in advance, have a nice day.
Let's say that you define your custom facade in app/Facades/MyDBFacade.php
<?php
namespace App\Facades;
use Illuminate\Support\Facades\DB;
class MyDBFacade extends DB
{
// ...
}
You just need to change single line in config/app.php, from
'DB' => Illuminate\Support\Facades\DB::class,
to
'DB' => App\Facades\MyDBFacade::class,
And it all should work now.
You can create / extend your Facade like this:
<?php namespace YourNameSpace\Facades;
class MyDBFacade extends Illuminate\Support\Facades\DB {
/**
* Create your custom methods here...
*/
public static function anyMethod($active)
{
/// do what you have to do
}
}
And then replace (or add it as a new one) to your app/config/app.php:
'aliases' => array(
'MyDBFacade' => 'YourNameSpace\Facades\MyEventFacade::class',
),
Remember to execute composer dump-autoload at the end.
Hope this helps!
Related
I need to be able to use a function (redirect with some parameters) from different controlers of my application.
I need to use $this->_helper->redirector($param1, $param2), and declare it just one time somewhere. Then I'll put this function in others controllers. If one day I modify the function, I don't need to modify it in each controller.
What I'm looking for is an equivalent of Symfony's services I guess.
Thanks for help :) .
What you 're asking for is called controller plugin in Laminas or Zend. You can code your own controller plugin, that you can use in every controller you want.
<?php
declare(strict_types=1);
namespace Application\Controller\Plugin;
use Laminas\Mvc\Controller\Plugin\AbstractPlugin;
class YourPlugin extends AbstractPlugin
{
public function __invoke($param1, $param2)
{
// your logic here
}
}
You have nothing more to do as to mention this plugin in your module.config.php file.
'controller_plugins' => [
'aliases' => [
'doSomething' => \Application\Controler\Plugin\YourPlugin::class,
],
'factories' => [
\Application\Controller\Plugin\YourPlugin::class => \Laminas\ServiceManager\Factory\InvokableFactory::class,
]
]
If you want to use some dependencies in your controller plugin, you can write your own factory for your plugin and add that dependencies via injection.
As your new plugin is mentioned in the application config, you can call your plugin in every controller you want.
<?php
declare(strict_types=1);
namespace Application\Controller;
class YourController extends AbstractActionController
{
public function indexAction()
{
$this->doSomething('bla', 'blubb');
}
}
Please do not use traits as a solution for your issue. Laminas / Zends already ships a redirect controller plugin. Perhaps a ready to use solution is already there or you can extend the redirect controller plugin ...
Service containers / providers are probably much simpler concepts than I imagine, but after several hours of reading I still don't get it, entirely.
I have created a simple DateFormat class within app/Library. After creating an alias for it inside \config\app.php I can use it right away in any controllers or blade templates.
<?php namespace App\Library;
class DateFormat {
public static function getDate($timestamp){
// processing the timestamp
}
}
Did I just create a Service Container? If yes, do I need to create a Service Provider as well? Where come bindings into the picture?
I would really appreciate some light on the subject.
Thanks
No. What you created is simply an alias to your class. Services Providers are a way of binding a specific class, and often are used in conjuction with a Facade.
An alias is simply a convenient way to use a class without having to import the entire namespaced class every time.
For example, if you have a class \My\Very\Long\Class\Adapter, you could alias this in config/app.php:
// config/app.php
<?php
'aliases' => [
// a bunch of aliases
'MyAdapter' => My\Very\Long\Class\Adapter::class,
]
And now you can just do:
<?php
new MyAdapter();
...
instead of:
<?php
use My\Very\Long\Class\Adapter;
...
new Adapter();
...
A Service Provider is often used when you want to resolve a dependency, most commonly through injection. This can be helpful when the class you want to resolve requires parameters to passed into the constructor or has a common setup every time. You can perform all that setup in the Provider.
Here's a scenario:
You have an API that you want to interact with. We'll call it SuperApi. The docs for SuperAPI say that to create an instance of the SuperApi class, you have to do something like:
<?php
// Some method (a controller or something)
public function index()
{
$superApi = new \SuperApi\Connector($key, $secret);
return $superApi->getCustomers();
}
Now, every time you want to create an instance of this, you'll have to do the same setup (or abstract it to some class, but the fact remains that you need to pass a $key and $secret to the constructor).
If you were to create an alias for this Connector class, maybe it would be:
// config/app.php
<?php
'aliases' => [
// a bunch of aliases
'SuperApi' => SuperApi\Connector::class,
]
So with that alias, you can now do this:
<?php
// Some method (a controller or something)
public function index()
{
$superApi = new SuperApi($key, $secret);
return $superApi->getCustomers();
}
But you see, that even with the alias, you still need to pass the $key and $secret.
This is where a Service Provider can help.
// app/Providers/SuperApiProvider.php
<?php
namespace App\Providers;
use SuperApi\Connector;
use Illuminate\Support\ServiceProvider;
class SuperApiProvider extends ServiceProvider
{
/**
* Register bindings in the container.
*
* #return void
*/
public function register()
{
$this->app->bind('superApiConnector', function ($app) {
return new ApiConnector($app['config']->get('super-api.key'), $app['config']->get('super-api.secret'));
});
}
}
// app/Providers/SuperApi.php (the Facade)
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Facade;
class SuperApi extends Facade
{
protected static function getFacadeAccessor()
{
return 'superApiConnector';
}
}
// config/super-api.config
<?php
return [
'key' => env('SUPER_API_KEY'),
'secret' => env('SUPER_API_SECRET'),
];
// config/app.php
<?php
'providers' => [
// a bunch of providers
App\Providers\SuperApiProvider::class,
]
See that the string you bind to in the provider ('superApiConnector') is the same as what you return from the facade and the class name of the facade is how you'll actually call the binded class, in this case SuperApi.
Now, when you want to user the SuperApi\Connector class, you can do this:
<?php
// Some method (a controller or something)
public function index()
{
return SuperApi::getCustomers();
}
And as I said above, where a provider really comes in handy is when you want to inject it and have Laravel's IoC Container automatically resolve the injected class:
<?php
// Some method (a controller or something)
public function index(SuperApi $api)
{
return $api->getCustomers();
}
To be clear, you do NOT need a Service Provider to take advantage of dependency injection. As long as the class can be resolved by the application it can be injected. That means whatever arguments the constructor of the class you're injecting takes need to also be auto-resolvable.
As for the title I've googled about two hours searching for a efficient answer and read repeatedly the official documentation, but without any step further, considering I'm relatively new to the framework. The doubt arise while searching for a correct way to share some code between controllers and i stumbled in service providers, so:
I've created say a MyCustomServiceProvider;
I've added it to the providers and aliases arrays within the app.php file;
finally I've created a custom helpers class and registered it like:
class MyCustomServiceProvider extends ServiceProvider
{
public function boot()
{
//
}
public function register()
{
$this->app->bind('App\Helpers\Commander', function(){
return new Commander();
});
}
}
So far, however, if I use that custom class within a controller I necessarily need to add the path to it through the use statement:
use App\Helpers\Commander;
otherwise I get a nice class not found exception and obviously my controller does not his job.
I suspect there's something which escapes to me on service providers! :-)
So far, however, if I use that custom class within a controller I
necessarily need to add the path to it through the use statement:
`use App\Helpers\Commander;`
otherwise I get a nice class not found
exception and obviously my controller does not his job.
Yes, that's how it works. If you don't want to use the full name, you can use a Facade instead.
Create the Facade class like this:
class Commander extends Facade
{
protected static function getFacadeAccessor() { return 'commander'; }
}
register the service:
$this->app->singleton('commander', function ($app) {
return new Commander();
});
add the alias to your config/app.php:
'aliases' => [
//...
'Commander' => Path\To\Facades\Commander::class,
//...
],
and use it like a Facade:
\Commander::doStuff();
On why your code still works, even when you remove the bind:
When you type-hint a parameter to a function, and Laravel does not know about the type you want (through binding), Laravel will do its best to create that class for you, if it is possible. So even though you didn't bind the class, Laravel will happily create a instance of that class for you. Where you actually need the binding is when you use interfaces. Usually, you'd not type-hint specific classes but a interface. But Laravel can not create a instance of an interface and pass it to you, so Laravel needs to know how it can construct a class which implements the interface you need. In this case, you'd bind the class (or the closure which creates the class) to the interface.
I have created the following custom class that I'd like to use in my Yii2 application:
#common/components/helper/CustomDateTime.php
namespace common\components\helper;
class CustomDateTime{function Now() {...}}
I want to use this class like this:
public function actionDelete($id)
{
$account = $this->findModel($id);
$account->archived = 1;
$account->archived_date = CustomDateTime::Now();
$account->save();
return $this->redirect(['index']);
}
In my #common/config/bootstrap.php file I've created a classMap according to this http://www.yiiframework.com/doc-2.0/guide-concept-autoloading.html.
Yii::$classMap['CustomDateTime'] = '#common/components/helper/CustomDateTime.php';
But I am getting the error: Class 'app\controllers\myapp\CustomDateTime' not found
QUESTION: How do I create a classMap so that I don't have to use the use statement at the beginning of every controller to access my custom class?
Yii 1.1 used to have an option in the config file to 'import' a set of code so that a class file could be autoloaded when it was called.
SOLUTION
Many thanks to #Animir for redirecting me back to the original documentation. http://www.yiiframework.com/doc-2.0/guide-concept-autoloading.html.
I found that I can use the following in my #common/config/bootstrap.php file
Yii::$classMap['CustomDateTime'] = '#common/components/helper/CustomDateTime.php';
BUT - it only works when the the CustomDateTime.php file does NOT have a declared namespace.
//namespace common\components\helper;
class CustomDateTime{function Now() {...}}
Just add use statement in file, where you use a class.
use common\components\helper\CustomDateTime;
/* some code */
public function actionDelete($id)
{
$dateNow = CustomDateTime::Now();
/* some code */
}
/* some code */
You can do this way too without the use of use
Yii::$app->cdt->Now(); // cdt - CustomDateTime
but for this thing to get accomplished successfully you add below to app/config/web.php (the config file)
...
'components' => [
'cdt' => [
'class' => 'common\components\helper\CustomDateTime',
],
...
]
...
Auto load in Yii 2 is pretty easy. You can use it by loading the class with config main file. like
You have created your class in components/helper/CustomDateTime.php . and now in your config/main.php in the top of the file add below code
require_once( dirname(__FILE__) . '/../components/helper/CustomDateTime.php');
Now your class is autoloaded in your project where ever you want to use it you can use like in your controller,model or view
Simply use like this
CustomDateTime-><methodName>();
Try this i have used this in my project.
For refrence you can use this link. click here
I know it's been long since this question was asked. I came across this and to share what I do.
I usually use an alias after use statement instead of adding 100 of lines of use statements for each model or class objects. Adding classMap for many of the classes that you use is not a good idea in my view. If you do that you'll be just adding unnecessary mapping even when you are not using those objects.
Here's what I do
use Yii;
use common\helpers as Helper;
use yii\helpers as YiiHelper;
use common\models as Model;
use common\components as Component;
And in the controller
public function actionIndex(){
$model = Model\SomeModel();
if(Yii::$app->request->isPost){
$post = Yii::$app->request->post('SomeModel');
$model->text = Helper\Text::clean($post['text']);
$model->text = YiiHelper\Html::encode($model->text);
if($model->save()){
return $this->render('thank_you');
}
}
}
Hope this helps :)
Good day!
The more I read, the more I get confused about this. What is the difference between a Facade and Aliases?
I have this Class:
/app/libraries/Project/Data.php
namespace PJ;
class Data {
// It is much like a data container, with static methods and properties for saving info
}
And the corresponding facade, so I can access by using just PJD:: .
According to some webpage around:
... Laravel Facades are proxies. They wrap around and call functions
on the underlying true implementation of the code. Further, in the
context of a Laravel application, these Facades are accessed by
assigning them to aliases. This use of the Dependency Injection
container allow you to reference something like
Illuminate\Support\Facades\Filesystem by simply calling File.
(http://ryantablada.com/post/proxies-service-locators-alias-facades-and-war)
But, I've also found and successfully tested that adding something like:
__app/config/app.php__
'aliases' => array(
//....,
'PJD' => 'PJ\Data',
),
I can also access my class the same way.
So, what's the difference?
Thanks
EDIT #01
I have created a class named Data in /app/libraries/Project/Data.php
namespace PJ;
class Data {
// It is much like a data container, with static methods and properties for saving info
}
I have a Facade Class for this Class Data /app/libraries/Project/DataFacade.php
use Illuminate\Support\Facades\Facade;
class PJD extends Facade {
protected static function getFacadeAccessor() {
return 'PJData';
}
}
And I have a Service Provider for them: /app/libraries/Project/DataServiceProvider.php
use Illuminate\Support\ServiceProvider;
class DataServiceProvider extends ServiceProvider {
public function register() {
$this->app->singleton('PJData', function() {
return new PJ\Data;
});
}
}
I also have added to /app/config/app.php:
'providers' => array(
// ....
'DataServiceProvider',
),
and in composer.json I've added a psr-4 line to direct PJ namespace to /app/libraries/Project
"psr-4": {
"PJ\\": "app/libraries/Project"
},
By doing all this, I can access my class from anywhere in the project just by PJD:: instead of PJ\Data::.
However, I've also noticed that just by adding to /app/config/app.php
'aliases' => array(
//....,
'PJD' => 'PJ\Data',
),
I get exactly the same result without all that facades and ServiceProviders. So, what's the point of one or another?
Thanks, and sorry for the large post.
Facade and Alias are two totally different concepts.
you can not access PJ\Data\ by PJD:: unless you have setup alias in the service provider while binding.
If you are accessing it, without defining it in config/app.php, then you have set it up in the service provider file itself.
Definition of alias,
used to indicate that a named person is also known or more familiar under another specified name.
It simply means you are giving a different name to the class so that it will be easier to call.
e.g.
if you have a class like this: Foo\Bar\AVeryLongNamespaceClassName\Data, you can just give an alias, (e.g. PJD) and access its methods and properties by this alias.
Note:
Unit testing is an important aspect of why facades work the way that they do. In fact, testability is the primary reason for facades to even exist.