问题
I would like to create helper functions to avoid repeating code between views in Laravel 5:
view.blade.php
<p>Foo Formated text: {{ fooFormatText($text) }}</p>
They\'re basically text formatting functions. Where and how can I create a file with these functions?
回答1:
Create a helpers.php
file in your app folder and load it up with composer:
"autoload": {
"classmap": [
...
],
"psr-4": {
"App\\": "app/"
},
"files": [
"app/helpers.php" // <---- ADD THIS
]
},
After adding that to your composer.json
file, run the following command:
composer dump-autoload
If you don't like keeping your helpers.php
file in your app
directory (because it's not a PSR-4 namespaced class file), you can do what the laravel.com
website does: store the helpers.php
in the bootstrap directory. Remember to set it in your composer.json
file:
"files": [
"bootstrap/helpers.php"
]
回答2:
Custom Classes in Laravel 5, the Easy Way
This answer is applicable to general custom classes within Laravel. For a more Blade-specific answer, see Custom Blade Directives in Laravel 5.
Step 1: Create your Helpers (or other custom class) file and give it a matching namespace. Write your class and method:
<?php // Code within app\Helpers\Helper.php
namespace App\Helpers;
class Helper
{
public static function shout(string $string)
{
return strtoupper($string);
}
}
Step 2: Create an alias:
<?php // Code within config/app.php
'aliases' => [
...
'Helper' => App\Helpers\Helper::class,
...
Step 3: Run composer dump-autoload
in the project root
Step 4: Use it in your Blade template:
<!-- Code within resources/views/template.blade.php -->
{!! Helper::shout('this is how to use autoloading correctly!!') !!}
Extra Credit: Use this class anywhere in your Laravel app:
<?php // Code within app/Http/Controllers/SomeController.php
namespace App\Http\Controllers;
use Helper;
class SomeController extends Controller
{
public function __construct()
{
Helper::shout('now i\'m using my helper class in a controller!!');
}
...
Source: http://www.php-fig.org/psr/psr-4/
Why it works: https://github.com/laravel/framework/blob/master/src/Illuminate/Support/ClassLoader.php
Where autoloading originates from: http://php.net/manual/en/language.oop5.autoload.php
回答3:
my initial thought was the composer autoload as well, but it didn't feel very Laravel 5ish to me. L5 makes heavy use of Service Providers, they are what bootstraps your application.
To start off I created a folder in my app
directory called Helpers
. Then within the Helpers
folder I added files for functions I wanted to add. Having a folder with multiple files allows us to avoid one big file that gets too long and unmanageable.
Next I created a HelperServiceProvider.php
by running the artisan command:
artisan make:provider HelperServiceProvider
Within the register
method I added this snippet
public function register()
{
foreach (glob(app_path().'/Helpers/*.php') as $filename){
require_once($filename);
}
}
lastly register the service provider in your config/app.php
in the providers array
'providers' => [
'App\Providers\HelperServiceProvider',
]
now any file in your Helpers
directory is loaded, and ready for use.
UPDATE 2016-02-22
There are a lot of good options here, but if my answer works for you, I went ahead and made a package for including helpers this way. You can either use the package for inspiration or feel free to download it with Composer as well. It has some built in helpers that I use often (but which are all inactive by default) and allows you to make your own custom helpers with a simple Artisan generator. It also addresses the suggestion one responder had of using a mapper and allows you to explicitly define the custom helpers to load, or by default, automatically load all PHP files in your helper directory. Feedback and PRs are much appreciated!
composer require browner12/helpers
Github: browner12/helpers
回答4:
This is what is suggested by JeffreyWay
in this Laracasts Discussion.
- Within your
app/Http
directory, create ahelpers.php
file and add your functions. - Within
composer.json
, in theautoload
block, add"files": ["app/Http/helpers.php"]
. - Run
composer dump-autoload
.
回答5:
Having sifted through a variety of answers on SO and Google, I still couldn't find an optimal approach. Most answers suggest we leave the application and rely on 3rd party tool Composer to do the job, but I'm not convinced coupling to a tool just to include a file is wise.
Andrew Brown's answer came the closest to how I think it should be approached, but (at least in 5.1), the service provider step is unnecessary. Heisian's answer highlights the use of PSR-4
which brings us one step closer. Here's my final implementation for helpers in views:
First, create a helper file anywhere in your apps directory, with a namespace:
namespace App\Helpers;
class BobFinder
{
static function bob()
{
return '<strong>Bob?! Is that you?!</strong>';
}
}
Next, alias your class in config\app.php
, in the aliases
array:
'aliases' => [
// Other aliases
'BobFinder' => App\Helpers\BobFinder::class
]
And that should be all you need to do. PSR-4
and the alias should expose the helper to your views, so in your view, if you type:
{!! BobFinder::bob() !!}
It should output:
<strong>Bob?! Is that you?!</strong>
回答6:
Custom Blade Directives in Laravel 5
Yes, there is another way to do this!
Step 1: Register a custom Blade directive:
<?php // code in app/Providers/AppServiceProvider.php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Blade; // <-- This is important! Without it you'll get an exception.
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
// Make a custom blade directive:
Blade::directive('shout', function ($string) {
return trim(strtoupper($string), '(\'\')');
});
// And another one for good measure:
Blade::directive('customLink', function () {
return '<a href="#">Custom Link</a>';
});
}
...
Step 2: Use your custom Blade directive:
<!-- // code in resources/views/view.blade.php -->
@shout('this is my custom blade directive!!')
<br />
@customLink
Outputs:
THIS IS MY CUSTOM BLADE DIRECTIVE!!
Custom Link
Source: https://laravel.com/docs/5.1/blade#extending-blade
Additional Reading: https://mattstauffer.co/blog/custom-conditionals-with-laravels-blade-directives
If you want to learn how to best make custom classes that you can use anywhere, see Custom Classes in Laravel 5, the Easy Way
回答7:
This is my HelpersProvider.php file:
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class HelperServiceProvider extends ServiceProvider
{
protected $helpers = [
// Add your helpers in here
];
/**
* Bootstrap the application services.
*/
public function boot()
{
//
}
/**
* Register the application services.
*/
public function register()
{
foreach ($this->helpers as $helper) {
$helper_path = app_path().'/Helpers/'.$helper.'.php';
if (\File::isFile($helper_path)) {
require_once $helper_path;
}
}
}
}
You should create a folder called Helpers
under the app
folder, then create file called whatever.php
inside and add the string whatever
inside the $helpers array.
Done!
Edit
I'm no longer using this option, I'm currently using composer to load static files like helpers.
You can add the helpers directly at:
...
"autoload": {
"files": [
"app/helpers/my_helper.php",
...
]
},
...
回答8:
For Custom Helper Libraries in my Laravel project, I have created a folder with name Libraries
in my Laravel/App
Directory and within Libraries directory, I have created various files for different helper libraries.
After creating my helper files I simply include all those files in my composer.json file like this
...
"autoload": {
"classmap": [
"database"
],
"files": [
"app/Libraries/commonFunctions.php"
],
"psr-4": {
"App\\": "app/"
}
},
...
and execute
composer dump-autoload
回答9:
Since OP asked for best practices, I think we're still missing some good advices here.
A single helpers.php file is far from a good practice. Firstly because you mix a lot of different kind of functions, so you're against the good coding principles. Moreover, this could hurt not only the code documentation but also the code metrics like Cyclomatic Complexity, Maintainability Index and Halstead Volume. The more functions you have the more it gets worse.
Code documentation would be Ok using tools like phpDocumentor, but using Sami it won't render procedural files. Laravel API documentation is such a case - there's no helper functions documentation: https://laravel.com/api/5.4
Code metrics can be analyzed with tools like PhpMetrics. Using PhpMetrics version 1.x to analyze Laravel 5.4 framework code will give you very bad CC/MI/HV metrics for both src/Illuminate/Foundation/helpers.php and src/Illuminate/Support/helpers.php files.
Multiple contextual helper files (eg. string_helpers.php, array_helpers.php, etc.) would certainly improve those bad metrics resulting in an easier code to mantain. Depending on the code documentation generator used this would be good enough.
It can be further improved by using helper classes with static methods so they can be contextualized using namespaces. Just like how Laravel already does with Illuminate\Support\Str and Illuminate\Support\Arr classes. This improves both code metrics/organization and documentation. Class aliases could be used to make them easier to use.
Structuring with classes makes the code organization and documentation better but on the other hand we end up loosing those great short and easy to remember global functions. We can further improve that approach by creating function aliases to those static classes methods. This can be done either manually or dynamically.
Laravel internally use the first approach by declaring functions in the procedural helper files that maps to the static classes methods. This might be not the ideal thing as you need to redeclare all the stuff (docblocks/arguments).
I personally use a dynamic approach with a HelperServiceProvider
class that create those functions in the execution time:
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class HelperServiceProvider extends ServiceProvider
{
/**
* The helper mappings for the application.
*
* @var array
*/
protected $helpers = [
'uppercase' => 'App\Support\Helpers\StringHelper::uppercase',
'lowercase' => 'App\Support\Helpers\StringHelper::lowercase',
];
/**
* Bootstrap the application helpers.
*
* @return void
*/
public function boot()
{
foreach ($this->helpers as $alias => $method) {
if (!function_exists($alias)) {
eval("function {$alias}(...\$args) { return {$method}(...\$args); }");
}
}
}
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
//
}
}
One can say this is over engineering but I don't think so. It works pretty well and contrary to what might be expected it does not cost relevant execution time at least when using PHP 7.x.
回答10:
instead of including your custom helper class, you can actually add to your config/app.php
file under aliases.
should be look like this.
'aliases' => [
...
...
'Helper' => App\Http\Services\Helper::class,
]
and then to your Controller, include the Helper using the method 'use Helper' so you can simply call some of the method on your Helper class.
eg. Helper::some_function();
or in resources view you can directly call the Helper class already.
eg. {{Helper::foo()}}
But this is still the developer coding style approach to be followed. We may have different way of solving problems, and i just want to share what i have too for beginners.
回答11:
Here's a bash shell script I created to make Laravel 5 facades very quickly.
Run this in your Laravel 5 installation directory.
Call it like this:
make_facade.sh -f <facade_name> -n '<namespace_prefix>'
Example:
make_facade.sh -f helper -n 'App\MyApp'
If you run that example, it will create the directories Facades
and Providers
under 'your_laravel_installation_dir/app/MyApp'.
It will create the following 3 files and will also output them to the screen:
./app/MyApp/Facades/Helper.php
./app/MyApp/Facades/HelperFacade.php
./app/MyApp/Providers/HelperServiceProvider.php
After it is done, it will display a message similar to the following:
===========================
Finished
===========================
Add these lines to config/app.php:
----------------------------------
Providers: App\MyApp\Providers\HelperServiceProvider,
Alias: 'Helper' => 'App\MyApp\Facades\HelperFacade',
So update the Providers and Alias list in 'config/app.php'
Run composer -o dumpautoload
The "./app/MyApp/Facades/Helper.php" will originally look like this:
<?php
namespace App\MyApp\Facades;
class Helper
{
//
}
Now just add your methods in "./app/MyApp/Facades/Helper.php".
Here is what "./app/MyApp/Facades/Helper.php" looks like after I added a Helper function.
<?php
namespace App\MyApp\Facades;
use Request;
class Helper
{
public function isActive($pattern = null, $include_class = false)
{
return ((Request::is($pattern)) ? (($include_class) ? 'class="active"' : 'active' ) : '');
}
}
This is how it would be called:
===============================
{!! Helper::isActive('help', true) !!}
This function expects a pattern and can accept an optional second boolean argument.
If the current URL matches the pattern passed to it, it will output 'active' (or 'class="active"' if you add 'true' as a second argument to the function call).
I use it to highlight the menu that is active.
Below is the source code for my script. I hope you find it useful and please let me know if you have any problems with it.
#!/bin/bash
display_syntax(){
echo ""
echo " The Syntax is like this:"
echo " ========================"
echo " "$(basename $0)" -f <facade_name> -n '<namespace_prefix>'"
echo ""
echo " Example:"
echo " ========"
echo " "$(basename $0) -f test -n "'App\MyAppDirectory'"
echo ""
}
if [ $# -ne 4 ]
then
echo ""
display_syntax
exit
else
# Use > 0 to consume one or more arguments per pass in the loop (e.g.
# some arguments don't have a corresponding value to go with it such
# as in the --default example).
while [[ $# > 0 ]]
do
key="$1"
case $key in
-n|--namespace_prefix)
namespace_prefix_in="$2"
echo ""
shift # past argument
;;
-f|--facade)
facade_name_in="$2"
shift # past argument
;;
*)
# unknown option
;;
esac
shift # past argument or value
done
fi
echo Facade Name = ${facade_name_in}
echo Namespace Prefix = $(echo ${namespace_prefix_in} | sed -e 's#\\#\\\\#')
echo ""
}
function display_start_banner(){
echo '**********************************************************'
echo '* STARTING LARAVEL MAKE FACADE SCRIPT'
echo '**********************************************************'
}
# Init the Vars that I can in the beginning
function init_and_export_vars(){
echo
echo "INIT and EXPORT VARS"
echo "===================="
# Substitution Tokens:
#
# Tokens:
# {namespace_prefix}
# {namespace_prefix_lowerfirstchar}
# {facade_name_upcase}
# {facade_name_lowercase}
#
namespace_prefix=$(echo ${namespace_prefix_in} | sed -e 's#\\#\\\\#')
namespace_prefix_lowerfirstchar=$(echo ${namespace_prefix_in} | sed -e 's#\\#/#g' -e 's/^\(.\)/\l\1/g')
facade_name_upcase=$(echo ${facade_name_in} | sed -e 's/\b\(.\)/\u\1/')
facade_name_lowercase=$(echo ${facade_name_in} | awk '{print tolower($0)}')
# Filename: {facade_name_upcase}.php - SOURCE TEMPLATE
source_template='<?php
namespace {namespace_prefix}\Facades;
class {facade_name_upcase}
{
//
}
'
# Filename: {facade_name_upcase}ServiceProvider.php - SERVICE PROVIDER TEMPLATE
serviceProvider_template='<?php
namespace {namespace_prefix}\Providers;
use Illuminate\Support\ServiceProvider;
use App;
class {facade_name_upcase}ServiceProvider extends ServiceProvider {
public function boot()
{
//
}
public function register()
{
App::bind("{facade_name_lowercase}", function()
{
return new \{namespace_prefix}\Facades\{facade_name_upcase};
});
}
}
'
# {facade_name_upcase}Facade.php - FACADE TEMPLATE
facade_template='<?php
namespace {namespace_prefix}\Facades;
use Illuminate\Support\Facades\Facade;
class {facade_name_upcase}Facade extends Facade {
protected static function getFacadeAccessor() { return "{facade_name_lowercase}"; }
}
'
}
function checkDirectoryExists(){
if [ ! -d ${namespace_prefix_lowerfirstchar} ]
then
echo ""
echo "Can't find the namespace: "${namespace_prefix_in}
echo ""
echo "*** NOTE:"
echo " Make sure the namspace directory exists and"
echo " you use quotes around the namespace_prefix."
echo ""
display_syntax
exit
fi
}
function makeDirectories(){
echo "Make Directories"
echo "================"
mkdir -p ${namespace_prefix_lowerfirstchar}/Facades
mkdir -p ${namespace_prefix_lowerfirstchar}/Providers
mkdir -p ${namespace_prefix_lowerfirstchar}/Facades
}
function createSourceTemplate(){
source_template=$(echo "${source_template}" | sed -e 's/{namespace_prefix}/'${namespace_prefix}'/g' -e 's/{facade_name_upcase}/'${facade_name_upcase}'/g' -e 's/{facade_name_lowercase}/'${facade_name_lowercase}'/g')
echo "Create Source Template:"
echo "======================="
echo "${source_template}"
echo ""
echo "${source_template}" > ./${namespace_prefix_lowerfirstchar}/Facades/${facade_name_upcase}.php
}
function createServiceProviderTemplate(){
serviceProvider_template=$(echo "${serviceProvider_template}" | sed -e 's/{namespace_prefix}/'${namespace_prefix}'/g' -e 's/{facade_name_upcase}/'${facade_name_upcase}'/g' -e 's/{facade_name_lowercase}/'${facade_name_lowercase}'/g')
echo "Create ServiceProvider Template:"
echo "================================"
echo "${serviceProvider_template}"
echo ""
echo "${serviceProvider_template}" > ./${namespace_prefix_lowerfirstchar}/Providers/${facade_name_upcase}ServiceProvider.php
}
function createFacadeTemplate(){
facade_template=$(echo "${facade_template}" | sed -e 's/{namespace_prefix}/'${namespace_prefix}'/g' -e 's/{facade_name_upcase}/'${facade_name_upcase}'/g' -e 's/{facade_name_lowercase}/'${facade_name_lowercase}'/g')
echo "Create Facade Template:"
echo "======================="
echo "${facade_template}"
echo ""
echo "${facade_template}" > ./${namespace_prefix_lowerfirstchar}/Facades/${facade_name_upcase}Facade.php
}
function serviceProviderPrompt(){
echo "Providers: ${namespace_prefix_in}\Providers\\${facade_name_upcase}ServiceProvider,"
}
function aliasPrompt(){
echo "Alias: '"${facade_name_upcase}"' => '"${namespace_prefix_in}"\Facades\\${facade_name_upcase}Facade',"
}
#
# END FUNCTION DECLARATIONS
#
###########################
## START RUNNING SCRIPT ##
###########################
display_start_banner
init_and_export_vars
makeDirectories
checkDirectoryExists
echo ""
createSourceTemplate
createServiceProviderTemplate
createFacadeTemplate
echo ""
echo "==========================="
echo " Finished TEST"
echo "==========================="
echo ""
echo "Add these lines to config/app.php:"
echo "----------------------------------"
serviceProviderPrompt
aliasPrompt
echo ""
回答12:
Create custom helpers’ directory: First create Helpers directory in app directory. Create hlper class definition: Let’s now create a simple helper function that will concatenate two strings. Create a new file MyFuncs.php in /app/Helpers/MyFuncs.php Add the following code
<?php
namespace App\Helpers;
class MyFuncs {
public static function full_name($first_name,$last_name) {
return $first_name . ', '. $last_name;
}
}
namespace App\Helpers; defines the Helpers namespace under App namespace. class MyFuncs {…} defines the helper class MyFuncs. public static function full_name($first_name,$last_name) {…} defines a static function that accepts two string parameters and returns a concatenated string
Helpers service provide class
Service providers are used to auto load classes. We will need to define a service provider that will load all of our helper classes in /app/Helpers directory.
Run the following artisan command:
php artisan make:provider HelperServiceProvider
The file will be created in /app/Providers/HelperServiceProvider.php
Open /app/Providers/HelperServiceProvider.php
Add the following code:
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class HelperServiceProvider extends ServiceProvider {
/**
* Bootstrap the application services.
*
* @return void
*/
public function boot()
{
//
}
/**
* Register the application services.
*
* @return void
*/
public function register()
{
foreach (glob(app_path().'/Helpers/*.php') as $filename){
require_once($filename);
}
}
}
HERE,
namespace App\Providers; defines the namespace provider
use Illuminate\Support\ServiceProvider; imports the ServiceProvider class namespace
class HelperServiceProvider extends ServiceProvider {…} defines a class HelperServiceProvider that extends the ServiceProvider class
public function boot(){…} bootstraps the application service
public function register(){…} is the function that loads the helpers
foreach (glob(app_path().'/Helpers/*.php') as $filename){…} loops through all the files in /app/Helpers directory and loads them.
We now need to register the HelperServiceProvider and create an alias for our helpers.
Open /config/app.php
file
Locate the providers array variable
Add the following line
App\Providers\HelperServiceProvider::class,
Locate the aliases array variable
Add the following line
'MyFuncs' => App\Helpers\MyFuncs::class,
Save the changes Using our custom helper
We will create a route that will call our custom helper function Open /app/routes.php
Add the following route definition
Route::get('/func', function () {
return MyFuncs::full_name("John","Doe");
});
HERE,
return MyFuncs::full_name("John","Doe"); calls the static function full_name in MyFuncs class
回答13:
First create helpers.php inside App\Http directory. Then add the following code inside the composer.json
"autoload": {
"classmap": [
"database"
],
"files": [
"app/Http/helpers.php"
],
"psr-4": {
"App\\": "app/"
}
},
Next run the following command
composer dump-autoload
Now you can define your custom function inside the helpers.php file.
回答14:
Another Way that I used was: 1) created a file in app\FolderName\fileName.php and had this code inside it i.e
<?php
namespace App\library
{
class hrapplication{
public static function libData(){
return "Data";
}
}
}
?>
2) After that in our blade
$FmyFunctions = new \App\FolderName\classsName;
echo $is_ok = ($FmyFunctions->libData());
that's it. and it works
回答15:
Best Practice to write custom helpers is
1) Inside the app
directory of the project root, create a folder named Helpers (Just to separate and structure the code).
2) Inside the folder write psr-4 files or normal php files
If the PHP files are in the format of psr-4 then it will be auto loaded, else add the following line in the composer.json which is inside the project root directory
Inside the autoload
key, create a new key named files
to load files at the time of auto load,inside the files
object add the path starting from app directory., here is an example.
"autoload": {
"classmap": [
"database"
],
"psr-4": {
"App\\": "app/"
},
"files": [
"app/Helpers/customHelpers.php"
]
},
"autoload-dev": {
"classmap": [
"tests/TestCase.php"
]
},
PS : try running composer dump-autoload
if the file dosen't loaded.
回答16:
Create Helpers.php in app/Helper/Helpers.php
namespace App\Helper
class Helpers
{
}
Add in composer and composer update
"autoload": {
"classmap": [
"database/seeds",
"database/factories",
"database","app/Helper/Helpers.php"
],
"psr-4": {
"App\\": "app/"
},
"files": ["app/Helper/Helpers.php"]
},
use in Controller
use App\Helper\Helpers
use in view change in config->app.php file
'aliases' => [
...
'Helpers' => 'App\Helper\Helpers'
],
call in view
<?php echo Helpers::function_name(); ?>
回答17:
in dir bootstrap\autoload.php
require __DIR__.'/../vendor/autoload.php';
require __DIR__.'/../app/Helpers/function.php'; //add
add this file
app\Helpers\function.php
回答18:
**
- Status Helper
** create new helper
<?php
namespace App\Helpers;
use Illuminate\Database\Eloquent\Collection;
class StatusHelper
{
protected static $_status = [
1=> [
'value' => 1,
'displayName' => 'Active',
],
2 => [
'value' => 2,
'displayName' => 'Inactive',
],
3 => [
'value' => 3,
'displayName' => 'Delete',
],
];
public static function getStatusesList()
{
$status = (new Collection(self::$_status))->pluck('displayName', 'value')->toArray();
return $status;
}
}
Use for the controller and any view file
use App\Helpers\StatusHelper;
class ExampleController extends Controller
{
public function index()
{
$statusList = StatusHelper::getStatusesList();
return view('example.index', compact('statusList'));
}
}
回答19:
In laravel 5.3 and above, the laravel team moved all procedural files (routes.php
) out of the app/
directory, and the entire app/
folder is psr-4
autoloaded. The accepted answer will work in this case but it doesn't feel right to me.
So what I did was I created a helpers/
directory at the root of my project and put the helper files inside of that, and in my composer.json
file I did this:
...
"autoload": {
"classmap": [
"database"
],
"psr-4": {
"App\\": "app/"
},
"files": [
"helpers/ui_helpers.php"
]
},
...
This way my app/
directory is still a psr-4 autoloaded one, and the helpers are a little better organized.
Hope this helps someone.
回答20:
There are some great answers here but i think this is the simplest. In Laravel 5.4 (and prob earlier versions too) you can create a class somewhere convenient for you, eg App/Libraries/Helper.php
class Helper() {
public function uppercasePara($str) {
return '<p>' .strtoupper($str). '<p>;
}
}
Then you can simply call it in your Blade template like this:
@inject('helper', \App\Libraries\Helper)
{{ $helper->drawTimeSelector() }}
If you don't want to use @inject then just make the 'uppercasePara' function as static and embed the call in your Blade template like this:
{{ \App\Libraries\Helper::drawTimeSelector() }}
No need for aliases. Laravel resolves the concrete class automatically.
来源:https://stackoverflow.com/questions/28290332/best-practices-for-custom-helpers-in-laravel-5