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.

SiZE
  • 2,217
  • 1
  • 13
  • 24
intumwa
  • 334
  • 2
  • 4
  • 15

10 Answers10

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();
?>
Bharat Chauhan
  • 3,204
  • 5
  • 39
  • 52
  • 4
    The logic does it all except that in the view it should be `$this->context->Hello()` instead of `$this->Hello()` – intumwa Feb 16 '16 at 09:09
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();
Sammaye
  • 43,242
  • 7
  • 104
  • 146
  • Yes. Maybe need add write in /baisc/config/web.php - ? And how it make? –  Юрий Светлов Feb 18 '16 at 11:16
  • @ЮрийСветлов I just put it in common/helpers (I use advanced app) and I do it exactly as shown in the Github repo – Sammaye Feb 18 '16 at 11:53
  • Show me please link Github on example. –  Юрий Светлов Feb 18 '16 at 12:21
  • @ЮрийСветлов for example this is the array helper: https://github.com/yiisoft/yii2/blob/master/framework/helpers/BaseArrayHelper.php that provides globals for array handling – Sammaye Feb 18 '16 at 12:24
  • 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) – cool Mar 07 '16 at 01:56
  • @ЮрийСветлов, i was faced with the same problem. I think, you just forget define namespace in the MyHelpers class. You should make like this: ` – Nikoole Dec 22 '16 at 07:51
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()?>">
meysam
  • 1,754
  • 2
  • 20
  • 30
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.

smsalisbury
  • 345
  • 4
  • 15
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.

Nana Partykar
  • 10,556
  • 10
  • 48
  • 77
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
}
mohit
  • 1,878
  • 1
  • 16
  • 27
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);
elixir
  • 1,394
  • 1
  • 11
  • 21
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;
            }
        }
    }
Thomas Rohde
  • 37
  • 1
  • 8
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();
    }

}
Songwut K.
  • 166
  • 1
  • 5
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.