How to override Yii core classes

Long term would it not be better if Yii core changed CHtml to some sort of Composite class patter. Where there are formatter classes that can be set as a setting and if nothing is set the default Yii core formatter class would be used. Long term this way we could support different doc types and standards IE: xhtml vs html5 and developers can customise the output of CHtml. CHtml is a static class/methods. I am not experienced enough to say what would be a good or bad architecture or how that would affect our options.

I am a little new to OOP and Yii, but from what I have learnt so far that sounds like something that could work.

That’s what i expect from Yii 2.0, too. But meanwhile we need to deal with Yii 1.x and that’s what the workaround is for. In 2.0 i’d like to see a pluggable CHtml class for bootstrap, foundation or any other CSS library.

Hi, I did just like you said here but it doesn’t seem to work, do you have something in your config file ?




'import'=>array(

	'application.models.*',

	'application.components.*',

	'application.extentions.*',

	'application.helpers.*',

),



Yes, you have to import your class. Please read my first post again carefully.




'application.components.CHtml',



Yes, I didn’t add this line of code in the import, because I thought that ‘application.components.*’, will do the job. But I ended up not using this method because I don’t want to update that file every time, and some errors might come up somewhere.

I actually quite like the idea of cloning and merging the Yii framework repository. If you simply added a namespace to the core CHtml class and made no other changes, then you’d never have to deal with merge conflicts. You could then write your own globally namespaced CHtml class and extend the core class directly within your projects in the way you’re already suggesting.

I don’t see any real downsides to that; it just means that the cloned version of the framework will only be useable in projects where you’ve overridden CHtml.

Is there any reason why CHtml use self:: to call static members of itself instead of CHtml::?

This means that my extended CHtml class need to override all entry points instead of just the protected activeInputField to set some properties of form fields used by screen readers depending on the status of the attribute. (required, has error, reference to the div containing the error message)

Eventually I think part of this may be useful in an upstream patch for CHtml but for now I like to use the extended CHtml approach.

I’ve solved the risk of forgetting this step by adding this code in index.php to be executed on servers in development mode (but not on production servers).




    // Verify that components/core/Html is correctly updated

    // when updating to a new framework.

    $stock_chtml = file_get_contents(str_replace('yii.php', '', $yii) . 'web/helpers/CHtml.php');

    // change CHtml => Html in the in-memory copy of the stock CHtml class

    $stock_chtml = str_replace('class CHtml', 'class Html', $stock_chtml);

    $core_html = file_get_contents('../protected/components/core/Html.php');

    if($core_html != $stock_chtml) {

        throw new Exception('protected/components/core/Html.php is not up to date.');

    }



You need to update the path to your Html.php if your protected directory is not located in the parent directory of index.php.

This way my application will die with an error message if I forget step 3 rather than giving subtle errors. On my dev server, the two compared files will likely end up in some cache of my hard drive or in the OS, and thus not slow down the page views noticeable.

This topic was brought up by my colleague, so if anybody is still struggling with this, here is a working solution I came up with some years ago.


<?php

$cacheFile = Yii::app()->getRuntimePath() . DIRECTORY_SEPARATOR . 'yii_core_chtml_' . md5_file(__FILE__) . '_' . str_replace('.', '_', Yii::getVersion()) . '.php';

if(!file_exists($cacheFile)){

    $file = Yii::getPathOfAlias('system.web.helpers.CHtml') . '.php';

    $source = str_replace(['<?php', 'self::'], ['','static::'], file_get_contents($file));

    $source = "<?php\nnamespace yii_core;\nuse Yii, CJavaScriptExpression;\n$source";

    file_put_contents($cacheFile, $source);

}

require_once $cacheFile;


class CHtml extends yii_core\CHtml {

  // here you can do whatever you wish, override any method etc. 

  // Above we replaced all self:: with static:: which activated LSB 

}



Then you just override internal class mapping in application config, like this:




<?php

// let's say this is file containing Yii app config


return [

    //...

    'import'      => [

        'app.components.CHtml',

    ],

    //...

]