Yii2 Create Extension Tutorial

Hello,

I am trying to create some extensions for Yii2.

I am quite new to composer.

Is there a tutorial how to create a new [size=2]extension for Yii2?[/size]

[size=2]

[/size]

[size=2]What I am missing in the Guide is the development lifecycle, e.g.[/size]

[size=2]

[/size]

[size=2]* Create a new directory somewhere aside the app or in an existing application structure to test?)[/size]

[size=2]* If the extension lies aside the app, do I always need to check in changes and run composer update in the testing app?[/size]

[size=2]

[/size]

[size=2]Thanks in advance.[/size]

[size=2]

[/size]

[size=2]Regards,[/size]

[size=2]

[/size]

[size=2]Joachim[/size]

extension/module is almost an application but it must be used within application. of course you can make application from extension and vise versa but you need extension.

i use next structure (advanced app)


ROOT_DIR

--frontend

--backend

-----web

--------index.php

--modules

----my_module_1     (namespace mega_module_1)

----my_module_2

dir ‘my_module_1’ has same structure as applications within ‘frontend’ or ‘backend’.

easiest way to include module into dev application is to make namespace alias in app config like




[

    'aliases' => [

'@base' => '@app/../'

        '@mega_module_1' => '@base/modules/my_module_1',

    ],

]



of course, you can put module where you want, just make proper alias

when finished, push my_module_1 into gist with autoloading in composer.json




// class autoloading specs

    "autoload": {

        "psr-4": {

            "whatever\\your\\namespace\\is": ""

        }

    }



then you can test including your module via composer

p.s.

just forgot! to enable module in application of course you need include it in config




'modules' => [

'your_module_alias' => [ 'class' => 'mega_module_1' ]

],



When you have developed your extension, and are ready to test composer deploy/install/update then add it to your applications composer.json, but use a source map:


	"repositories": [

    	{

        	"type": "vcs",

        	"url": "https://github.com/jacmoe/phileTableOfContents"

    	}

	],

	"require": {

    	"php": ">=5.4.0",

    	"twig/twig": "1.15.*",

    	"jacmoe/table-of-contents": "dev-master",



Whenever you push to your git repository, you need to run a composer update.

And when you’ve done testing and development, you can remove the entry in ‘repositories’ and submit your project to Packagist.

jacmoe,

cool. good to know new stuff. thanks

Just found out yesterday that one can even use a file url:




"repositories":


        {

            "type": "vcs",

            "url": "C:/xampp/htdocs/path/to/yii2-myextension"

        }

    ]



I still need to commit changes, but ist stays local during the dev. cycle.

Regards,

Joachim

Awesome - that’s even easier! :)

I wanted to point out, that you can mimic a Composer 3rd party library, locally. It does not need to be under version control, have live edits, and still works with Gii :)

For example, I want to create a new extension. I plan to put it on Github and Packagist so it can be installed easily via Composer. However, I don’t want to commit my changes to my version control system (Git) in order for it to work. I don’t want to have to run “composer update” after every change. I want to make a change and see it live instantly. And this is TOTALLY POSSIBLE!

This is the best way to develop new extensions for Yii!

First, create a new directory for your new extension in your htdocs, then init Composer:




mkdir yii2-myextension

cd yii2-myextension

composer init



Follow the interactive wizard. Now, open "composer.json", either with your editor, vim, or nano.

Here is an example of mine (I removed keywords, description, ect because they aren’t important. You should have them, but my description isn’t relevant to you.




{

    "name": "wadeshuler/yii2-myextension",

    "type": "yii2-extension",

    "minimum-stability": "dev",

    "autoload": {

        "psr-4": {

            "wadeshuler\\myextension\\": ""

        }

    }

}



Name: The name is <vendor>/yii2-<extension>. I use my GitHub username (WadeShuler), all lowercase and no spaces (wadeshuler). It would help if you create a GitHub account first, and also create a Packagist account. Packagist uses your GitHub username :) Keep those 3 in sync and you will reduce issues. You should also prefix your extensions with “yii2-”. It is a Yii standard practice, helps others know it is for Yii2 and not Yii1.

Type: You must use "yii2-extension" for the type, this tells Yii to load it into your extensions file for internal use. Click here to read more.

Min Stability: it is important to use "dev" here during testing. We have no version control (yet) and we will force our main Yii2 composer.json to accept a "dev" dependency even though Yii2 requires stable, by using "@dev" for the repo (shown later).

Autoload: I use PSR-4 and you probably should too. Most Yii2 packages I have encountered are PRS4. I feel it is better an easier, I don’t just follow suit to be a sheep :P Notice how it has my vendor name, “wadeshuler” then double backslashes. These are important. If you don’t know about the double backslashes, then read here. It then has the name of my extension. However, there is no “yii2” in it. This is actually the namespace we are going to use, we can call it whatever we want, so we can omit the “yii2-” to be cleaner and easier to write later. This is the namespace that defines where your extension is located. Here in Composer, we are saying “wadeshuler/whateveriwant” is going to be our namespace, and it is located “” <-- root dir of the loaded extension. You could do “wadeshuler\\myextension\\”: “/src” <-- in your extensions src directory if you want to put everything in a “src” dir and just have your “README”, “LICENSE” and “composer.json” in your extensions root dir.

Ok, so here, your Yii2 extension is ready for use in Composer. We will add files later, using Gii. Right now, there is nothing but “composer.json” in our directory. Gii will whip up the namespace, Module class, BaseController, all that for us :)

Open your Yii2 app’s “composer.json” file, lets add our extension.




    "require-dev": {

        "wadeshuler/yii2-myextension": "@dev"

    },

    "repositories": [

        {

            "type": "path",

            "url": "/Applications/XAMPP/xamppfiles/htdocs/yii2-myextension"

        }

    ],



You probably don’t have a “repositories” section, so add it. Notice we use “path” for the type, this does not require any version control :) For the url, I use the full path to the extension I am currently working on. This will actually create a symbolic link to the directory, which is key for live editing! I added my extension to the “require-dev” section, because it is development. Just in case this was pushed to the server, I don’t want to break anything. When it’s all done and on Packagist, I would put it where it belongs and remove the entry in “repositories” so it loads from Packagist and not my local computer.

Now we are ready to run:


composer update

If everything is correct, you should see Composer load your library when watching your terminal output. Open your Yii2 app in your editor and view the "vendor" directory, look for your namespace dir (wadeshuler for me), then under it you should see a directory for your extension. Now, it is empty. If it loaded fine, you are ready to start building your extension. All changes are live in your main Yii app so you can test while coding!

So lets get our extension up and running. Now, if you don’t need any controller routes or views (it isn’t directly accessed via a route), you should use an Object. It loads less files in the backend than a Module. This would work for say a helper class.




namespace wadeshuler\myextension;


Class Helper extends \yii\base\Object

{

    public static function _die($data)

    {

        die( '<pre>' . print_r($data, true) . '</pre>' );

    }

}



Then to use it:




use wadeshuler\myextension\Helper; //Helper is name of the class we made above


$test = [ 'one', 'two', 'three' ];

Helper::_die($test);



Ok, so thats a base of an Object for some helper class you want to build. What if you need more than that? Lets first break down when to use an Object, Component, or Module. It is important to know that ALL 3 can accept default configurations by adding it to your Yii2 config.

So this tells us that an Object is a stripped down Component. A Component is an Object with “event” and “behavior” abilities. Now, a Module is a mini-app that have MVC, bootstrapping, and dependency injection. If you wanted to create a plug-n-play forum or blog, you would create a Module. You could perfect it, put it on GitHub and Packagist, and load the whole forum or blog feature into your apps in literally, seconds. Do not create a module just to create a simple helper class. It takes extra memory and CPU to do these. Actually, if you trace a Module back, you will see it is an Object at heart too :) Module extends “yii\di\ServiceLocator” which extends “yii\base\Component” which extends “yii\base\Object”.

If you need routes, controllers, views: Module

If you need events and behaviors: Component

If you don’t need any of that extra jazz: Object

So what about Gii? Gii can create a Module for you and it also has a “extension” generator. Now, I find the extension generator useless. It puts it in your runtime directory, does the composer for you (not the way I showed above though), and creates an “AutoloadExample” that extends a Widget. 3 files total. I don’t want them in my runtime dir, and I don’t want a widget 99% of the time, and I like to have my extension that is under dev in another text editor (Atom) window for separation. So that is 3 strikes. Even if I did want a widget, I could easily add the few lines to setup the Class myself.

For Modules though, Gii is nice. It will build the controller and views for us. The beautiful thing, when you input your namespace into Gii properly, it will actually put the files into your directory outside of Yii because Composer made the path a symbolic link! So i have a separate Atom editor open for my new extension, and the module files are instantly in there for me to edit, even though it is outside of my actual Yii app!

After generating a module, all you have to do is add it to your Yii config:




    'modules' => [

        'myextension' => [

            'class' => 'wadeshuler\myextension\Module',

            'param1' => 'foo',

            'param2' => 'bar'

        ]

    ],



You can then access it in your site: http://localhost/yii2-app/web/myextension

So what about an Object? There is no "object" section for our config! Well, you have 2 options.

I normally just put it under ‘components’, because an Object is almost identical to a Component, except a Component has event and behavior support. I think it is fair game to place an Object under your ‘components’ config, however they guys at Yii frowned upon it and cried about using DI. I have seen many many public extensions put an Object under ‘components’.

Another option, is to use DI. You could put it under the ‘bootstrap’ section of your Yii config and pass config params that way. You would have to implement the BootstrapInterface for this. Not too difficult, but an extra hoop to jump through.

I hope this helps someone. I am going to add a page to the Yii wiki "how-to" section for the Composer steps.

1 Like