I want a new config file in my Laravel 5 app to store all my constants in. After looking around the net I found the recommended solution seems to be to create a new config file that returns an array of key value pairs and then use that. So I created the following file:
<?php
// config/constants.php
return [
'SITE_NAME' => 'Site Name',
'SITE_EMAIL' => 'email#site.com',
'ADMIN_EMAIL' => 'admin#site.com'
];
Then in one of my controllers I try to access one of these values like so:
echo Config::get('constants.ADMIN_EMAIL');
I just get the following error:
FatalErrorException in WelcomeController.php line 46:
Class 'App\Http\Controllers\Config' not found
Do I have to do something else to get it to work?
In Laravel 5, to avoid this kind of headache, you can use the config helper function to get a config item, like this :
config('constants.ADMIN_EMAIL')
Nice and easy ;)
The Config class is an alias in the global namespace. To reference it from inside the controller (which is in the App\Http\Controllers namespace) you have to prepend it with a backslash:
echo \Config::get('constants.ADMIN_EMAIL');
Or add a use statement above the controller class:
use Config;
class MyController extends Controller {
As an alternative you might also want to use dependency injection to access the config. That would look somewhat like this:
class MyController extends Controller {
public function __construct(Illuminate\Config\Repository $config){
$this->config = $config;
}
public function index(){
echo $this->config->get('constants.ADMIN_EMAIL');
}
}
As #Bernig suggests you can also simply use the new config() helper function:
echo config('constants.ADMIN_EMAIL');
I met the same issue today, and I find an elegant solution:
add the config/your_new_config.php to ConfigServiceProvider, like this:
/**
* Overwrite any vendor / package configuration.
*
* This service provider is intended to provide a convenient location for you
* to overwrite any "vendor" or package configuration that you may want to
* modify before the application handles the incoming request / command.
*
* #return void
*/
public function register()
{
config([
'config/your_new_config.php', // add your new config file here!
]);
}
The reason is well explained in the function's comments
Related
I have two controller file homecontroller and backendcontroller. What is the best way to create global function and access it from both files?
I found here Arian Acosta's answer helpful but I wonder if there is an easiest way. I would appreciate any suggestions.
Solution
One way to do this is to create a class and use its instance, this way you can not only access the object of the class within a controller, blade, or any other class as well.
AppHelper file
In you app folder create a folder named Helpers and within it create a file name AppHelper or any of your choice
<?php
namespace App\Helpers;
class AppHelper
{
public function bladeHelper($someValue)
{
return "increment $someValue";
}
public function startQueryLog()
{
\DB::enableQueryLog();
}
public function showQueries()
{
dd(\DB::getQueryLog());
}
public static function instance()
{
return new AppHelper();
}
}
Usage
In a controller
When in a controller you can call the various functions
public function index()
{
//some code
//need to debug query
\App\Helpers\AppHelper::instance()->startQueryLog();
//some code that executes queries
\App\Helpers\AppHelper::instance()->showQueries();
}
In a blade file
Say you were in a blade file, here is how you can call the app blade helper function
some html code
{{ \App\Helpers\AppHelper::instance()->bladeHelper($value) }}
and then some html code
Reduce the overhead of namespace (Optional)
You can also reduce the overhead of call the complete function namespace \App\Helpers by creating alias for the AppHelper class in config\app.php
'aliases' => [
....
'AppHelper' => App\Helpers\AppHelper::class
]
and in your controller or your blade file, you can directly call
\AppHelper::instance()->functioName();
Easy Solution:
Create a new Helpers folder in your app directory.
Create a php file named your_helper_function.php in that Helpers directory.
Add your function(s) inside your_helper_function.php
function your_function($parameters){
//function logic
}
function your_another_function($parameters){
//function logic
}
Add this file to the Files key of your composer.json like
"autoload": {
...
"files": [
"app/Helpers/your_helper_function.php"
]
...
}
Finally, regenerate composer autoload files. (Run this in your project directory)
composer dump-autoload
That's it! and now you can access your_function() or your_another_function() in any part of your Laravel project.
If you still have any confusion, check my blog post on how to do this:
How to Add a Global Function in Laravel Using Composer?
Updated:
Step 1
Add folder inside app folder
app->Helper
Step 2
add php Class inside Helper folder
Eg. Helper.php
Add namespace and class to the Helper.php
namespace App\Helper;
class Helper
{
}
Register this Helper.php into config/app.php file
'aliases' => [
....
'Helper' => App\Helper\Helper::class
]
Now, write all the functions inside Helper.php and it will be accessible everywhere.
How to access from Controller?
Step 1 - Add a namespace at top of the controller.
use App\Helper\Helper;
Step 2 - Call function - Assume there a getInformation() inside the Helper Class.
$information = Helper::getInformation()
In your Controller.php which extends BaseController, you can create a function like;
public function data($arr = false)
{
$data['foo'] = 'bar';
return array_merge($data,$arr);
}
And from any controller when you send a data to a view;
public function example()
{
$data['smthg'] = 'smthgelse';
return view('myView',$this->data($data));
}
The data in the the main controller can be accessed from all controllers and blades.
The Laravel Service Provider way
I've been using global function within Laravel for a while and I want to share how I do it. It's kind of a mix between 2 answers in this post : https://stackoverflow.com/a/44021966/5543999 and https://stackoverflow.com/a/44024328/5543999
This way will load a file within a ServiceProvider and register it within your Laravel app.
Where is the difference, the scope, it's always about the scope.
Composer //Autload whitin composer.json method
|
|--->Laravel App //My method
|
|--->Controller //Trait method
|--->Blade //Trait method
|--->Listener //Trait method
|--->...
This is a really simplist way to explain my point, all three methods will achieve the purpose of the "Global function". The Traits method will need you to declare use App\Helpers\Trait; or App\Helpers\Trait::function().
The composer and service provider are almost about the same. For me, they answer better to the question of what is a global function, because they don't require to declare them on each place you want to use them. You just use them function(). The main difference is how you prefer things.
How to
Create the functions file : App\Functions\GlobalFunctions.php
//App\Functions\GlobalFunctions.php
<?php
function first_function()
{
//function logic
}
function second_function()
{
//function logic
}
Create a ServiceProvider:
//Into the console
php artisan make:provider GlobalFunctionsServiceProvider
Open the new file App\Providers\GlobalFunctionsServiceProvider.php and edit the register method
//App\Providers\GlobalFunctionsServiceProvider.php
public function register()
{
require_once base_path().'/app/Functions/GlobalFunctions.php';
}
Register your provider into App\Config\App.php wihtin the providers
//App\Config\App.php
'providers' => [
/*
* Laravel Framework Service Providers...
*/
Illuminate\Auth\AuthServiceProvider::class,
...
Illuminate\Validation\ValidationServiceProvider::class,
Illuminate\View\ViewServiceProvider::class,
App\Providers\GlobalFunctionsServiceProvider::class, //Add your service provider
Run some artisan's commands
//Into the console
php artisan clear-compiled
php artisan config:cache
Use your new global functions
//Use your function anywhere within your Laravel app
first_function();
second_function();
Laravel uses namespaces by default. So you need to follow the method described in that answer to setup a helper file.
Though in your case you want to access a method in different controllers. For this there's a simpler way. Add a method to you base controller app/Http/Controllers/Controller.php and you can access them in every other controller since they extend it.
// in app/Http/Controllers/Controller.php
protected function dummy()
{
return 'dummy';
}
// in homecontroller
$this->dummy();
There are a few ways, depending on the exact functionality you're trying to add.
1) Create a function inside Controller.php, and make all other controller extend that controller. You could somewhat compair this to the master.blade.php
2) Create a trait, a trait can do a lot for you, and keeping ur controllers clean. I personally love to use traits as it will look clean, keep my Controller.php from being a mess with tons of different lines of code.
Creating a global function
create a Helpers.php file under a folder, let's name it 'core'.
core
|
-- Helpers.php
namespace Helpers; // define Helper scope
if(!function_exists('html')) {
function html($string) {
// run some code
return $str;
}
}
In your composer.json
"autoload": {
"psr-4": {
},
"files": [
"core/Helpers.php"
]
}
in the file that you want to use it
// the " use " statement is not needed, core/Helpers is loaded on every page
if(condition_is_true) {
echo Helpers\html($string);die();
}
Remove the namespace in Helpers.php if you want to call your function without the need to prefix namespace. However I advise to leave it there.
Credit: https://dev.to/kingsconsult/how-to-create-laravel-8-helpers-function-global-function-d8n
By using composer.json and put the function containing file(globalhelper.php) to the autoload > files section, then run
composer dump-autoload
You can access the function inside the file(globalhelper.php) without having to calling the class name, just like using default php function.
I am trying to make my own custom Facade and register is with a custom service container and finally creating a custom alias for this facade.
I am not sure what part is not working, maybe there is a problem with the service container registering or maybe with the alias?
Let's start with my facade:
/**
*
* #see \App\Library\Facades\ViewWrapper\CustomView
*/
class CustomViewFacade extends Facade
{
protected static function getFacadeAccessor()
{
return 'customview';
}
}
My CustomView class with the logic and the show function
namespace App\Library\Facades\ViewWrapper;
...
class CustomView
{
public function show(...) { ... }
...
}
My CustomViewServiceProvider
namespace App\Providers;
...
class CustomViewServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* #return void
*/
public function register()
{
$this->app->singleton(CustomViewFacade::class);
$this->app->alias(CustomViewFacade::class, 'customview');
}
}
How I register the provider in the config\app.php
App\Providers\CustomViewServiceProvider::class,
How I create the alias in the config\app.php
'CustomView' => App\Library\Facades\ViewWrapper\CustomViewFacade::class
In my controller I use the facade like this:
use CustomView;
...
public function show(ImageRequest $imagerequest)
{
return CustomView::show(...);
}
I get the following error in the controller:
Class 'CustomView' not found
What am I doing wrong here?
EDIT
After clearing config and composer autoload dump I get the following error:
Call to undefined method App\Library\Facades\ViewWrapper\CustomViewFacade::show()
I think you haven't quite clearly understood how Facades work. They are just an easy way to access your services without having to deal with dependency injection. I'm not a fan of this methodology, but here's how you do it properly.
You need to bind your actual service to the container, not the facade. The facade is almost just a symbolic link to your service within the container.
You need to import the actual service, not the facade. Laravel will automatically bind your dependency in the type-hinted variable, thanks to its behind the scenes magic.
Use:
use App\Library\Facades\ViewWrapper\CustomView;
(small note: your namespace here should be your service's namespace, be aware to not mix up the semantic between facade and service. The service contains the logic, the facade is just an accessor to a service that is already injected. This is important!!)
Instead of:
use CustomView;
It should solve the issue.
Also, I'd suggest you do define how the class should be constructed and injected in the Service Container by using a Closure in the bootstrap function.
class CustomViewServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* #return void
*/
public function register()
{
$this->app->singleton(CustomView::class, function () {
return new CustomView(...);
);
}
}
Also, the alias function is not necessary in your case. It'd simply allow you to access the service by using the customview key in the Service Container.
Just define the Facade in your config/app.php file.
Another small suggestion: use PHP 7 class selectors instead of strings in your facade accessor definition. For example: CustomView::class intead of customview. It makes your code neater and easier to read.
Please run below command and check:
php artisan config:cache
php artisan cache:clear
I'm asking/answering because I have had so much trouble getting this working and I'd like to show a step-by-step implementation.
References:
https://laravel.com/docs/5.0/facades#creating-facades
http://www.n0impossible.com/article/how-to-create-facade-on-laravel-51
This may not be the only way to implement facades in Laravel 5, but here is how I did it.
We're going to create a custom Foo facade available in the Foobar namespace.
1. Create a custom class
First, for this example, I will be creating a new folder in my project. It will get its own namespace that will make it easier to find.
In my case the directory is called Foobar:
In here, we'll create a new PHP file with our class definition. In my case, I called it Foo.php.
<?php
// %LARAVEL_ROOT%/Foobar/Foo.php
namespace Foobar;
class Foo
{
public function Bar()
{
return 'got it!';
}
}
2. Create a facade class
In our fancy new folder, we can add a new PHP file for our facade. I'm going to call it FooFacade.php, and I'm putting it in a different namespace called Foobar\Facades. Keep in mind that the namespace in this case does not reflect the folder structure!
<?php
// %LARAVEL_ROO%/Foobar/FooFacade.php
namespace Foobar\Facades;
use Illuminate\Support\Facades\Facade;
class Foo extends Facade
{
protected static function getFacadeAccessor()
{
return 'foo'; // Keep this in mind
}
}
Bear in mind what you return in getFacadeAccessor as you will need that in a moment.
Also note that you are extending the existing Facade class here.
3. Create a new provider using php artisan
So now we need ourselves a fancy new provider. Thankfully we have the awesome artisan tool. In my case, I'm gonna call it FooProvider.
php artisan make:provider FooProvider
Bam! We've got a provider. Read more about service providers here. For now just know that it has two functions (boot and register) and we will add some code to register. We're going to bind our new provider our app:
$this->app->bind('foo', function () {
return new Foo; //Add the proper namespace at the top
});
So this bind('foo' portion is actually going to match up with what you put in your FooFacade.php code. Where I said return 'foo'; before, I want this bind to match that. (If I'd have said return 'wtv'; I'd say bind('wtv', here.)
Furthermore, we need to tell Laravel where to find Foo!
So at the top we add the namespace
use \Foobar\Foo;
Check out the whole file now:
<?php
// %LARAVEL_ROOT%/app/Providers/FooProvider.php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Foobar\Foo;
class FooProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* #return void
*/
public function boot()
{
//
}
/**
* Register the application services.
*
* #return void
*/
public function register()
{
$this->app->bind('foo', function () {
return new Foo;
});
}
}
Make sure you use Foobar\Foo and not Foobar\Facades\Foo - your IDE might suggest the wrong completion.
4. Add our references to config/app.php
Now we have to tell Laravel we're interested in using these random files we just created, and we can do that in our config/app.php file.
Add your provider class reference to 'providers': App\Providers\FooProvider::class
Add your facade class reference to 'aliases': 'Foo' => Foobar\Facades\Foo::class
Remember, in aliases, where I wrote 'Foo', you will want to put the name you want to reference your facade with there. So if you want to use MyBigOlFacade::helloWorld() around your app, you'd start that line with 'MyBigOlFacade' => MyApp\WhereEverMyFacadesAre\MyBigOlFacade::class
5. Update your composer.json
The last code change you should need is to update your composer.json's psr-4 spaces. You will have to add this:
"psr-4": {
"Foobar\\" : "Foobar/",
// Whatever you had already can stay
}
Final move
Okay so now that you have all that changed, the last thing you need is to refresh the caches in both composer and artisan. Try this:
composer dumpautoload
php artisan cache:clear
Usage & A Quick Test:
Create a route in app/routes.php:
Route::get('/foobar', 'FooBarController#testFoo');
Then run
php artisan make:controller FooBarController
And add some code so it now looks like this:
<?php
namespace App\Http\Controllers;
use Foobar\Facades\Foo;
use App\Http\Requests;
class FooBarController extends Controller
{
public function testFoo()
{
dd(Foo::Bar());
}
}
You should end up with the following string:
Troubleshooting
If you end up with and error saying it cannot find the class Foobar\Facades\Foo, try running php artisan optimize
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 :)
I've created provider class and put it into app/models/Providers directory:
<?php
//app/models/Providers/NiceUrlServiceProvider.php
namespace Providers;
use Illuminate\Support\ServiceProvider;
class NiceUrlServiceProvider extends ServiceProvider {
public function register()
{
$this->app->bind('niceurl', function()
{
return new \Utils\NiceUrl();
});
}
}
and facade class in app/models/Facades directory:
<?php
// app/models/Facades/NiceUrl.php
namespace Facades;
use Illuminate\Support\Facades\Facade;
class NiceUrl extends Facade {
protected static function getFacadeAccessor() { return 'niceurl'; }
}
I have also edited app/config/app.php and added this as provider:
'providers' => array(
// default ones
'Providers\NiceUrlServiceProvider',
),
and added alias to Facade:
'aliases' => array(
// default ones
'NiceUrl' => 'Facades\NiceUrl',
),
When I try to run my app I get:
Class 'Providers\NiceUrlServiceProvider' not found
*
* #param \Illuminate\Foundation\Application $app
* #param string $provider
* #return \Illuminate\Support\ServiceProvider
*/
public function createProvider(Application $app, $provider)
{
return new $provider($app); // this line marked as causing problem
}
However if I comment the line where I add my provider and in public/index.php put this code at the end of file:
$x = new \Providers\NiceUrlServiceProvider($app);
$x->register();
echo NiceUrl::create('some thing');
it works without a problem, so it does not seem to be a problem with autoloading.
Also if I register provider manually using:
$app->register('Providers\NiceUrlServiceProvider');
echo NiceUrl::create('some thing');
at the end of public/index.php it is working without a problem.
Questions:
How to make it work?
Where should I hold providers/facades files? Here I put them into model directory into separate folders.
The solution was quite simple but it was not obvious at all. After adding your provider you need to run:
composer dump-autoload
in your main project directory. It will generate new autoload_classmap.php file that will include your service provider. composer-update in this case also will work but it's not neccessary and it will take much more time. It's quite strange that it's necessary when you put provider into app/config/app.php and it's not necessary when you manually register provider but this is how it works.
The solution was quite simple but it was not obvious at all. After adding your provider you need to run:
composer dump-autoload
when you add some folder or other classes which is not in your composer.json autoload you would add it then run the above command.