Yii2 - How do I AutoLoad a custom class? - php

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 :)

Related

PHP Laravel 5.2 - Call function in another file [duplicate]

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.

laravel 5 : Extend a Facade

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!

Phalcon PHP multi module namespace definition

I'm using Phalcon PHP with Multi module application. I'm using namespace in my project but I'm searching for something to use theses namespace.
For example, in my view folder I'm using the models folder and in my controller I use the models folder too. But I'm using lot of class models to do a Phalcon find or findFirst. And the only way than I found to make this multi apps working, it's to define the namespace used to import the class like this :
use Apps\Common\Models\Users;
use Apps\Common\Models\Customers;
use Apps\Common\Models\Agents;
...
And I have 50 models like this in my apps... I don't want to define them in all my controller and all my view to make it work.
Do you have a solutions for that ?
Thanks.
If I understood correctly, you can omit the namespace declaration on top of your controller file:
use Models\News;
class NewsController extends BaseController
{
public function indexAction()
{
// With Use above
$obj = new News();
// Without Use above (full namespace path)
$obj = new \Models\News();
}
}

Laravel custom view helpers stop working if using namespace

I have followed some tutorials to create some global helper functions to use in blade views.
I have created ViewHelpers.php file in App\Helpers folder. This file contains the following code:
<?php
class ViewHelpers {
public static function bah()
{
echo 'blah';
}
}
Here is my service provider which loads my helpers (currently just one file):
<?php namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class HelperServiceProvider extends ServiceProvider {
public function register()
{
foreach (glob(app_path().'/Helpers/*.php') as $filename){
echo $filename; // for debugging - yes, I see it is getting called
require_once($filename);
}
}
}
I have added it to config\app.php in 'providers' section:
'App\Providers\HelperServiceProvider',
And now I call my helper in a blade view:
{{ViewHelpers::bah()}}
For now it works fine.
But if I change my ViewHelper namespace to this:
<?php namespace App\Helpers;
class ViewHelpers {
// omitted for brevity
my views fail with Class 'ViewHelpers' not found.
How do I make my views to see the ViewHelpers class even if it is in a different namespace? Where do I add use App\Helpers?
Another related question - can I make an alias for ViewHelpers class to make it look like, let's say, VH:bah() in my views?
And I'd prefer to do it in simple way, if possible (without Facades and what not) because these are just static helpers without any need for class instance and IoC.
I'm using Laravel 5.
You will get Class 'ViewHelpers' not found because there is no ViewHelpers, there is App\Helpers\ViewHelpers and you need to specify namespace (even in view).
You can register alias in config/app.php which will allow you to use VH::something():
'aliases' => [
// in the end just add:
'VH' => 'App\Helpers\ViewHelpers'
],
If your namespace is correct you do not even have to use providers - class will be loaded by Laravel.

Adding a new config file in Laravel 5 not working

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

Categories