i want to make a helper function that i use it widely in my project almost any where or some other helper functions that maybe used now as an example i have laravel request helper in mind like below :
request()->get('name);
now i know that any where in blade or controller or elsewhere if i use it it works .
now i have 2 questions .
1-how to make a helper like this that does something and can be used easily and widely
2-is that wise to make some helper like that ???
Create a helper class in app\Helpers\GlobalHelper.php
<?php
namespace App\Helpers;
class GlobalHelper
{
public static function helloWorld()
{
return "Hello World"
}
}
Then in your config\app.php in the aliases array add
'Helper' => App\Helpers\GlobalHelper::class,
Then in a blade file you can use {{ Helper::helloWorld() }} or in a controller you can use \Helper::helloWorld();
To make global helpers, you can do it like so.
Add a php file (not class) to the following the following path app/Helpers/helper.php.
if (! function_exists('helper')) {
function helper() {
return new Helper();
}
}
To make it similar to Laravels, the approach is to make an object you can call methods on the initial helper call will return.
class Helper {
public function getHelp() {
return 'did this help?';
}
}
Now get composer to autoload your file with the helper function.
"autoload": {
"files": [
"app/Helpers/helper.php"
]
}
This will enable you to call the following.
helper()->getHelp(); // returns: did this help?
For your last question.
Is is wise to make some helper like that?
In object oriented design this is an anti pattern as it deals with global functions and should be either static namespaced calls or objects. However in the context of Laravel i really enjoy what you can do with these helpers and right now, in my current project, we have global functions dealing with formatting floats to our locale money string representation that have helped a lot and is very pleasant to use.
Related
I have a PHP Laravel app that has an Elequent Model for EmailTokenUrlLogin and a Controller to login a user by accessing a URL with a token value in the URL.
I would like to have a function that will create a new Model/DB record to generate the token for a user and be able to call this function from any other Controller or Model in my app.
Right now I have it in my Login Controller however I am not happy with this as it requires either a POST request to post all the required function parameters or else a GET request with a long complicated URL of parameters.
So I want my function below generateShortLifeEmailTokenUrl($user_id, $email, $expireType, $expireNumber = '') to live somewhere in the app in which I can call it from anywhere.
Where would a function like below best be located and how to make it callable from other models and controllers?
public function generateShortLifeEmailTokenUrl($user_id, $email, $expireType, $expireNumber = '')
{
if(Auth::user()->isAdmin){
// generate a new token
// ... other logic here......
// create model and DB record and return the created token value
$emailTokenUrlLoginData = new EmailTokenUrlLogin;
$emailTokenUrlLoginData->user_id = $user_id;
$emailTokenUrlLoginData->email = $email;
$emailTokenUrlLoginData->token = $createToken();
$emailTokenUrlLoginData->expireType = $expireType;
$emailTokenUrlLoginData->expireNumber = $expireNumber;
$emailTokenUrlLoginData->save();
// return generated token
return $emailTokenUrlLoginData->token;
}
}
This really depends on how sophisticated you want to your code to be.
If you really just need this in one controller action, you can just place the code there. Or you can create a private method on that controller that does the job. Advanced programmers will consider this a bad practice, but for a small application it's good enough.
Alexeys suggestion with the global function works as well, but is considered an even worse practice because it's global. If you make all your functions global, your global scope and namespace will be full of unrelated stuff that will eventually get in the way of each other. Again, for a small application you will probably be fine, though.
Now, if you're curious about what a better practice would be: the keywords are services and dependency injection. That's not something I'm going to explain right here, but there are lots of resources on the web that will help you understand how these concepts work and what the benefits are.
Laravel has built in support for depencency injection, you can read all about it in the documentation.
Put it in a trait, and bind the trait to any other class where it is needed. You will not need to make it public that way, and can access it anywhere it is needed. Trait methods are compiled into the class as if there were native class methods, but can be overruled within the class as needed.
See: http://php.net/manual/en/language.oop5.traits.php
Trait EmailTokenTrait {
protected function generateShortLifeEmailTokenUrl($user_id, $email, $expireType, $expireNumber = '')
{
...
}
Bind the trait to whatever class:
<?php
namespace \some\namespace;
class SomeClass {
use \EmailTokenTrait;
protected function someFunction() {
$token = $this->generateShortLifeEmailTokenUrl($user_id, $email, $expireType);
}
}
Then autoload the trait.
"autoload": {
....
"files": [
"app/traits/EmailTokenTrait.php"
]
},
If you're working with this function a lot, you can create global helper:
if (! function_exists('generateShortLifeEmailTokenUrl')) {
function generateShortLifeEmailTokenUrl($user_id, $email, $expireType, $expireNumber = '')
{
....
}
}
Put it in helpers.php and add this to composer.json to load the helpers:
"autoload": {
....
"files": [
"app/someFolder/helpers.php"
]
},
What is best practice for making a function/method global to the application for several controllers?
For example lets say we have a controller. This controller is using a function, but instead of copy pasting it to another controller, we just want to make a call to that function.
class ControllerName extends AbstractActionController {
// Your actions
// Has to become a call,
// instead of copy pasting this function to several controllers
public function GlobalFunction ($parameter) {
//Use parameter and return something
}
}
Creating ControllerPlugins is one solution, I've also read about creating and setting up a StdLib. So what is the best practice for a function which will only be called at the controllers?
Two other related questions:
The plugin that is described in the accepted answer will do the job. But in what case you do NOT want to use a plugin and will go for another solution? I just want to brighten it up, since I did not find enough documentation about it.
Another point of interrest. What if this plugin has to be available to several modules aswell? Setting up the plugin within the application and setting it up in the module\Application\Config\module.config.php or within the Config\Autoload\Global.php of theZend App?
You probably want to look at the several Zend\Mvc\Controller\Plugin-Classes provided. Ultimately it all depends on what your "global function" is supposed to do. It may either be suited to do it as a ControllerPlugin or it may better be suited as a functionality provided by one of your Services.
To write your own ControllerPlugin, do it like the following:
namespace Yournamespace\Controller\Plugin;
use Zend\Mvc\Controller\Plugin\AbstractPlugin;
class YourPlugin extends AbstractPlugin
{
public function doSomething()
{
// ...
}
}
Register your plugin at configuration, either inside getConfig() with the top-level-array-key or inside your Modules getControllerPluginConfig() without the top-level:
'controller_plugins' => array(
'invokables' => array(
'yourPlugin' => 'Yournamespace\Controller\Plugin\YourPlugin',
)
),
And simply use it:
public function indexAction()
{
$plugin = $this->yourPlugin();
$plugin->doSomething();
return new ViewModel();
}
If you just want to call $this->yourPlugin($paramX, $paramY), then you have to define a __invoke() method to your ControllerPlugin.
Hope this helps.
Here is a simple view helper (notice the pass-by-reference argument):
class Zend_View_Helper_MyViewHelper extends Zend_View_Helper_Abstract
{
public function MyViewHelper(&$array)
{
unset($array['someExistingKey']);
}
}
This does not work in the view. $array['someExistingKey'] is still set (except within the immediate context of the method). Zend must be doing something to prevent the array from being passed in by reference. Any ideas on a solution?
When you call $this->MyViewHelper($array) from your templates you are not actually calling the helper class directly, Zend_View is instantiating the class and calling it for you. So I think you might have trouble getting this working. Your best bet is probably to use Zend_Registry, or refactor to take a different approach not requiring a global.
I just thought of a workaround. You just have to call the helper manually, instead of letting ZF call it through call_user_func_array.
Ref.php
class Zend_View_Helper_Ref extends Zend_View_Helper_Abstract
{
public function removeFromRef(&$ref)
{
// change your var value here
unset($ref['key']);
}
/**
* ZF calls this for us, but we'll call what we want, so you can skip this.
*/
// public function ref()
// {}
}
As you can see, you can skip the convention of having to name your main method as the filename, but I still recommend it.
Now, you can pass references in views/controllers:
// in view:
$this->getHelper('Ref')->removeFromRef($someVar2Change);
// in controller
$this->view->getHelper('Ref')->removeFromRef($someVar2Change);
Basically, this is what $this->ref() does: gets the helper, then calls call_user_func_array.
Some people may have problems using $this->getHelper('Ref')->ref() instead of $this->ref() though, but it works.
I have a scenario where I'm trying to incorporate several people's PHP work, some of it OOP and some not. I want to pull a library file of functions into a class and have those functions be available to other files that reference the class. I know I can just call the library functions directly, but then I would have to update all of the dependent files to do likewise. Example:
class do_something {
function test_state() {
...
}
if ($this->test_state($var)) {
...
}
}
Where test_state() is identical to the same-named function in the library file, making for redundant code to keep sync'd. That can be changed to:
class do_something {
if (test_state($var)) {
...
}
}
But that creates the aforementioned problem of $this->test_state() not being available to files dependent on the class. What I'd like to be able to do is something like:
class do_something {
public function test_state() = test_state();
if ($this->test_state($var)) {
...
}
}
Obviously, that's a very rough and incorrect example of what I'm trying to do... Is there any way in OOP to make that sort of reassignment, making the method of the same name as the function available within the class?
You can use a workaround to simulate this. In fact you would often want this approach to bolt on closures to objects in PHP. It leverages the magic __call method in PHP to redirect method calls to ordinary functions (beware: no $this available).
class do_something {
function __call($func, $args) {
if (isset($this->$func) && is_callable($this->$func)) {
return call_user_func_array($this->$func, $args);
}
}
}
Then you can "register" functions that you want to allow (or closures) with a simple assignment:
$do_something->function_name = "global_function_name";
$do_something->or_even = array("other_class", "method");
But again, this doesn't make them proper methods as such.
You'd create your base utility class, then extend it. See PHP's manual entry for inheritance for the details. I'm not saying this is the best solution for your exact situation, but I think it answers the question you were trying to get at.
What you're asking for isn't possible directly, but can be faked with a quick (horrible) hack:
class do_something {
public function test_state($param) {
return test_state($param);
}
...
$this->test_state($param);
...
}
Good luck with refactoring!
I want create a helper class that containing method like cleanArray, split_char, split_word, etc.
The helper class it self will be used with many class. example :
Class A will user Helper, Class B, Class C, D, E also user Helper Class
what the best way to write and use helper class in PHP ?
what i know is basic knowledge of OOP that in every Class that use Helper class must create a helper object.
$helper = new Helper();
It that right or may be some one can give me best way to do that.
I also will create XXX Class that may use Class A, B, C, etc.
UPDATE : ->FIXED my fault in split_word method :D
Based on Saul, Aram Kocharyan and alex answer, i modified my code, but its dont work, i dont know why.
<?php
class Helper {
static function split_word($text) {
$array = mb_split("\s", preg_replace( "/[^\p{L}|\p{Zs}]/u", " ", $text ));
return $this->clean_array($array);
}
static function split_char($text) {
return preg_split('/(?<!^)(?!$)/u', mb_strtolower(preg_replace( "/[^\p{L}]/u", "", $text )));
}
}
?>
and i use in other Class
<?php
include "Helper.php";
class LanguageDetection {
public function detectLanguage($text) {
$arrayOfChar = Helper::split_char($text);
$words = Helper::split_word($text);
return $arrayOfChar;
}
}
$i = new Detection();
print_r($i->detectLanguage("ab cd UEEef する ح خهعغ فق 12 34 ٢ ٣ .,}{ + _"));
?>
Helper classes are usually a sign of lack of knowledge about the Model's problem domain and considered an AntiPattern (or at least a Code Smell) by many. Move methods where they belong, e.g. on the objects on which properties they operate on, instead of collecting remotely related functions in static classes. Use Inheritance for classes that share the same behavior. Use Composition when objects are behaviorally different but need to share some functionality. Or use Traits.
The static Utils class you will often find in PHP is a code smell. People will throw more or less random functions into a class for organizing them. This is fine when you want to do procedural coding with PHP<5.2. As of 5.3 you would group those into a namespace instead. When you want to do OOP, you want to avoid static methods. You want your objects to have High Cohesion and Low Coupling. Static methods achieve the exact opposite. This will also make your code less testable.
Are Helper Classes Evil?
Killing the Helper class, part two
Functional Decomposition AntiPattern
Is the word "Helper" in a class name a code smell?
Moreover, every Class that use Helper class must create a helper object is a code smell. Your collaborators should not create other collaborators. Move creation of complex object graphs into Factories or Builders instead.
As a rule of thumb, helpers should contain functionality that is common but has no special designation under the overall architecture of the application.
Suffix the classname with Helper
Use static methods whenever possible
In short:
// Helper sample
//
class ConversionHelper {
static function helpThis() {
// code
}
static function helpThat() {
// code
}
}
// Usage sample
//
class User {
function createThings() {
$received = ConversionHelper::helpThis();
}
}
Instead of creating static class , you should just write simple functions , and include that file at the index/bootstrap file (you can even use namespaces with it).
Instead of:
class Helper {
static function split_word($text) { ...
static function split_char($text) { ...
}
It should be:
namespace Helper;
function split_word($text) { ...
function split_char($text) { ...
There is no point wrapping it all up in a class. Just because you put it in a class doesn't make it object oriented .. actually it does the exact oposite.
You could create a class with static methods...
class Str {
public static function split_char($str, $chr) {
...
}
}
You could also namespace a bunch of functions with a namespace, but I think the former is preferred.
Use public static methods in the class as such:
/* Common utility functions mainly for formatting, parsing etc. */
class CrayonUtil {
/* Creates an array of integers based on a given range string of format "int - int"
Eg. range_str('2 - 5'); */
public static function range_str($str) {
preg_match('#(\d+)\s*-\s*(\d+)#', $str, $matches);
if (count($matches) == 3) {
return range($matches[1], $matches[2]);
}
return FALSE;
}
// More here ...
}
Then invoke them like this:
CrayonUtil::range_str('5-6');
If in another file, use the following at the top:
require_once 'the_util_file.php';