How to write global functions in Yii2 and access them in any view (not the custom way)
Asked Answered
P

10

10

Yii1.1 had a CComponent class that had a CBaseController which was the base class for CController. There was a /protected/components/Controller.php class which enabled any function in that class to be accessed in any view.

Yii2 no longer possess the CComponent class. The Yii2 guide indicates that "Yii 2.0 breaks the CComponent class in 1.1 into two classes: yii\base\Object and yii\base\Component". Does anyone know how to write global functions in Yii2 and them in any view, just like it was in Yii1.1 using /protected/components/Controller.php?

A couple of similar topics discuss custom answers, but I would like to know whether there is an official way of doing that, not the custom way.

Post answered 27/7, 2015 at 11:14 Comment(1)
You should use component for global functions. The link you mentioned contains a simple example on how to do it.Harlie
G
9

Follow Step:
1) create following directory "backend/components"
2) create "BackendController.php" controller in "components" folder

<?php    
    namespace backend\components;
    use Yii;

    class BackendController extends \yii\web\Controller
    {
        public function init(){
            parent::init();

        }
        public function Hello(){
            return "Hello Yii2";
        }
    }

3) all backed controller extend to "BackendController" (like).

<?php
namespace backend\controllers;

use Yii;
use backend\components\BackendController;

class SiteController extends BackendController
{

    public function beforeAction($event)
    {
        return parent::beforeAction($event);
    }

    public function actionIndex(){
        /* You have to able for call hello function to any action and view */
        //$this->Hello(); exit;

        return $this->render('index');
    }
}

4) create your action view page "index.php" (like)

<?php
print $this->Hello();
?>
Gorky answered 27/7, 2015 at 12:48 Comment(1)
The logic does it all except that in the view it should be $this->context->Hello() instead of $this->Hello()Post
G
5

Controller functions are not accessible in the views.

In Yii1 the view attached to the controller whereas in Yii2 the view attaches to the View class (this was one of the core changes in Yii2). This separates the controller and view logic but also makes it harder for global functions, as you have noticed.

Yii2, itself, has also needed global functions. They have made "helpers", there are in fact a number of helpers: https://github.com/yiisoft/yii2/tree/master/framework/helpers each providing their own set of global functions for use.

If you haven't guessed yet, this is the best way to do globals in Yii2. It is also the standard compliant way as well (PSR-2 or whatever) and is considered better coding than normal globals.

So, you should actually be making your own custom helpers with your globals in, for example:

class MyHelpers
{
    public static function myGlobalToDoSomethingAwesome()
    {
        return $awesomeness;
    }
}

and just reference that in your view/controller like you would any helper:

use common\components\MyHelpers;
MyHelpers::myGlobalToDoSomethingAwesome();
Gamesome answered 27/7, 2015 at 23:34 Comment(6)
Yes. Maybe need add write in /baisc/config/web.php - ? And how it make?Warrantor
@ЮрийСветлов I just put it in common/helpers (I use advanced app) and I do it exactly as shown in the Github repoGamesome
Show me please link Github on example.Warrantor
@ЮрийСветлов for example this is the array helper: github.com/yiisoft/yii2/blob/master/framework/helpers/… that provides globals for array handlingGamesome
This works just fine and if you ask me it is much better way to define helpers/globals like this instead of defining it specifically for views controllers etc ... (unless there is a specific reason for that)Variscite
@ЮрийСветлов, i was faced with the same problem. I think, you just forget define namespace in the MyHelpers class. You should make like this: <?php namespace common\components; class MyHelpers { public static function myGlobalToDoSomethingAwesome() { return $awesomeness; } }Brashear
S
3

Easily you can create a component:

<?php

namespace frontend\components;

use yii\base\Component;

class MyComponent extends Component
{
    public function hello()
    {
        return "Hello, World!";
    }
}

Register it as a component in your frontend/config/main.php file:

return [
    'id' => 'app-frontend',
    'basePath' => dirname(__DIR__),
    // Some code goes here
    'components' => [
        // some code here
        'memem' => [
            'class' => 'frontend\components\MyComponent'
        ],
    ],
];

and finally use it where you need:

<?php

/* @var $this \yii\web\View */
/* @var $content string */

use yii\helpers\Html;
use yii\widgets\Breadcrumbs;
?>
<?php $this->beginPage()?>
<!DOCTYPE html>
<html>
<head>
  <meta charset="<?=Yii::$app->charset?>">
  <meta name="usage" value="<?=Yii::$app->memem->hello()?>">
Sightless answered 13/3, 2017 at 5:27 Comment(1)
Thank you so much for your big help, You saved me Thank youIbex
O
2

One option is to create a file (probably in your components directory) that has your functions in it:

function myFunction($parameters)
{
    // Do stuff and return stuff
}

and then include it in your index.php file:

require_once(__DIR__ . "../components/MyGlobalFunctions.php');

The disadvantage is that this is now outside the OOP scope of the application. I used this method to create a dd() (dump and die) function like Laravel has.

Octagon answered 27/7, 2015 at 21:22 Comment(0)
R
2

As, question is already answered. But, still I would like to answer it for future uses.

I'm using yii2-app-basic. [NOTE : Directory structure may differ for yii2-app-advanced.]

My Directory Structure:

->Root Folder
    ->assets
    ->commands
    .
    .
    ->controllers
        ->SiteController.php
        ->CommonController.php (New common controller created)
    ->mail
    .
    .
    ->modules
        ->users
            ->controllers
                ->UsersController.php
            ->models
                ->Users.php
            ->views
                ->index.php
            ->Users.php
    .
    .
    .

CommonController.php [Common controller(see in directory structure) which will be extended in all controller, if needed.]

<?php
namespace app\controllers;

use Yii;
use yii\web\Controller;

class CommonController extends Controller
{
    .
    .
    // I used this function for checking login access of user
    public function checkLoginAccess() {
        //Write your own custom code
        // For example
        $loginAccess = "No";
        if($loginAccess == "No") {
            Yii::$app->user->logout();
        }
    }
}

UsersController.php

<?php
namespace app\modules\users\controllers;

use Yii;
.
.
use app\controllers\CommonController;

//Extend CommonController 
class UsersController extends CommonController 
{
  // Inside init() function, use checkLoginAccess() method to be called
  public function init() {
    parent::init();
    if(!Yii::$app->user->isGuest) {
      $this->checkLoginAccess();
    }
  }
    .
    .
    .
}

So, Whenever this UsersController.php controller will come into an account, first init() method will be called, And in init() method CommonController method checkLoginAccess() will get call automatically. So, whenever a member having no login acess, he/she will be automatically logged out.

Hope it will help. Any Problem/Question, feel free to ask.

Republic answered 11/4, 2016 at 18:4 Comment(0)
I
1

You can also make components in YII2

Create a directory and a file same as in YII1 in frontend or backend and write below code in it

frontend/components/Controller.php

/**
 * Description of Controller
 *
 * @author mohit
 */

namespace frontend\components;
use Yii;
class Controller extends \yii\web\Controller{
    //put your code here

    public function beforeAction($action) {
        parent::beforeAction($action);
        if(true)
            return true;
        else
            return false;

    }
}

After that use it in every controller by extending this class like this-

namespace frontend\controllers;
use Yii;
use frontend\components\Controller;
class SomeController extends Controller
{
    // code
}
Ilex answered 27/7, 2015 at 11:25 Comment(0)
B
0

I have not started Yii2 but you should be able achieve similar functionality using static functions.

Create a class, let say "MyGlobalFunctions.php" with following contents

<?php
class MyGlobalFunctions{
    public static function myFunction($args){
       // logic here
     return someValu here
    }
}

in your views you can call this function as

MyGloabalFunctions::myFunction($args);
Broca answered 27/7, 2015 at 15:2 Comment(1)
this is exactly what Helper classes doStorytelling
P
0

I am new to Yii and tried this as solution for example messages that are shown in layout i created a baseController in frontend/components (all controllers extends this BaseController) and do the always needed stuff in the init section. and set the data to the view/layout with $this->view->params in view or layout use the data with $this->params i dont know if this is the best practice .. sorry for my bad english, i hope it helps

 namespace frontend\components;
    use Yii;
    use frontend\models\UserMessages;

    class BaseController extends \yii\web\Controller
    {
        public function init(){
            parent::init();

            // user nachrichten
            if (!Yii::$app->user->isGuest) {
                    $messages = UserMessages::find()
                    ->where(['user_recipient_id' => Yii::$app->user->identity->id])
                    ->orderBy('date_created')
                    ->all();
                    $this->view->params['userMessages'] = $messages;
            }
        }
    }
Pridemore answered 20/9, 2016 at 11:54 Comment(0)
S
0

https://www.yiiframework.com/wiki/747/write-use-a-custom-component-in-yii2-0

[ components/MyComponent.php ]

namespace app\components;


use Yii;
use yii\base\Component;
use yii\base\InvalidConfigException;

class MyComponent extends Component
{
 public function welcome()
 {
  echo "Hello..Welcome to MyComponent";
 }

}

[ config/web.php ]

..
..
'components' => [

         'mycomponent' => [

            'class' => 'app\components\MyComponent',

            ],
           ]
...
...

** Your controller *** [ controllers/TestController.php ]

namespace app\controllers;
use Yii;

class TestController extends \yii\web\Controller
{
    public function actionWelcome()
    {
       Yii::$app->mycomponent->welcome();
    }

}
Skywriting answered 24/4, 2020 at 3:35 Comment(0)
T
0

I know this is an old question, and the latest answer is still pretty old, so I thought I would put my 2 cents in for the 2023 fresh install of Yii2.

First I create a new folder called globals. Inside that, I created a php file called functions.php.

I place all of my global functions in there, I also did the same for classes.php

Here is an example for the functions

<?php
  use yii\helpers\Url;
  use yii\helpers\Html;
  use yii\helpers\HtmlPurifier;
  use yii\helpers\ArrayHelper;

  // cents: 0=never, 1=if needed, 2=always
  function formatMoney($number, $cents = 2) { 
    if (is_numeric($number)) {
      if (!$number) {
        $money = ($cents == 2 ? '0.00' : '0');
      } else {

        if (floor($number) == $number) {
          $money = number_format($number, ($cents == 2 ? 2 : 0));
        } else {
          $money = number_format(round($number, 2), ($cents == 0 ? 0 : 2));
        }
      }
      return '$'.$money;
    }
  }

  function formatPhoneNumber($phoneNumber) {
    $phoneNumber = preg_replace('/[^0-9]/','',$phoneNumber);

    if(strlen($phoneNumber) > 10) {
      $countryCode = substr($phoneNumber, 0, strlen($phoneNumber)-10);
      $areaCode = substr($phoneNumber, -10, 3);
      $nextThree = substr($phoneNumber, -7, 3);
      $lastFour = substr($phoneNumber, -4, 4);
      $phoneNumber = '+'.$countryCode.' ('.$areaCode.') '.$nextThree.'-'.$lastFour;
    }
    else if(strlen($phoneNumber) == 10) {
      $areaCode = substr($phoneNumber, 0, 3);
      $nextThree = substr($phoneNumber, 3, 3);
      $lastFour = substr($phoneNumber, 6, 4);
      $phoneNumber = '('.$areaCode.') '.$nextThree.'-'.$lastFour;
    }
    else if(strlen($phoneNumber) == 7) {
      $nextThree = substr($phoneNumber, 0, 3);
      $lastFour = substr($phoneNumber, 3, 4);
      $phoneNumber = $nextThree.'-'.$lastFour;
    }

    return $phoneNumber;
  }

Then in the root, I opened the composer.json file. After the

"scripts": {
...
}

I added:

    "autoload": {
        "files": [
            "\\globals\\functions.php"
        ]
    },

Then in the yii file, I added require_once(__DIR__ . '/globals/functions.php');

#!/usr/bin/env php
<?php
/**
 * Yii console bootstrap file.
 *
 * @link http://www.yiiframework.com/
 * @copyright Copyright (c) 2008 Yii Software LLC
 * @license http://www.yiiframework.com/license/
 */

defined('YII_DEBUG') or define('YII_DEBUG', true);
defined('YII_ENV') or define('YII_ENV', 'dev');

require __DIR__ . '/vendor/autoload.php';
require __DIR__ . '/vendor/yiisoft/yii2/Yii.php';

$config = require __DIR__ . '/config/console.php';

$application = new yii\console\Application($config);
require_once(__DIR__ . '/globals/functions.php');
$exitCode = $application->run();
exit($exitCode);

Once all of these changes have been made, I then ran composer update and the ./yii serve 0.0.0.0

Now you can use your functions as if they are in the file you are developing.

<?php foreach ($bills as $bill): ?>
      <tr>
        <th scope="row"><?= $bill['company_name'] ?></th>
        <td><a href="<?= $bill['company_website'] ?>" target="_blank"><?= $bill['company_credit_name'] ?></a></td>
        <td class="text-center"><?= $bill['type_name'] == 'credit' ? Icon::show('credit-card', ['class'=>'fa-2x']) : Icon::show('file-invoice-dollar', ['class'=>'fa-2x']) ?></td>
        <td class="text-center"><?= $bill['bill_autopay'] == '1' ? Icon::show('toggle-on', ['class'=>'fa-2x, toggle-on']) : Icon::show('toggle-on', ['class'=>'fa-2x, toggle-off']) ?></td>
        <td><?= formatMoney($bill['bill_credit']) ?></td>
        <td><?= formatMoney($bill['bill_balance']) ?></td>
        <td><?= formatMoney($bill['bill_payment']) ?></td>
        <td><?= $bill['bill_dueday'] ?></td>
        <td><?= $bill['bill_rate'] ?>%</td>
        <td><?= $bill['bill_cpi'] == '1' ? true : false ?></td>
        <td><?= formatMoney($bill['bill_perid']) ?></td>
      </tr>
    <?php endforeach; ?>

This is my take on how to do this.

Tephrite answered 7/1, 2023 at 19:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.