Yii2: How to create/develop a new extension using Composer locally without version control or Git

Using a version control system, like Git, is nice. However, when building an extension from scratch and loading it via Composer, it adds a lot of pain in the butt steps. You have to commit your changes, update composer to pull them over, then notice there is an error, fix, commit, update. repeat.. I don't want all my baby steps under Git. Sure, I could edit my commit history, but c'mon. Just let me code! I will put it under version control once I get a baseline created. This guide will show you how to setup your composer.json to load a local directory (everything inside, live). You make a change, save the file, refresh the page, boom.

What about after you have a release of your extension, but you want to work on it to add a new feature or fix a bug? It needs to be useable in Yii2 while you work on it. So again, we don't need all the extra steps. Using the instructions in this guide, you will be able to edit your composer.json to load the files live via a symbolic link. You won't have to commit or update to see your changes in your Yii app!

This is the best way to develop new extensions for Yii! It is also the best way to work on your already existing extensions to fix bugs or add new features!

First, lets create a directory for our new extension. I am on a Mac and use XAMPP, so your paths may vary. I don't want to put my extension inside my Yii2 app because it is separate, meant to be pushed to Git and Packagist, and shared with the world, and used later. It is independent, I am just using my Yii2 app as a testing ground to build it, even if I am planning on using it inside the app for real.

cd /Applications/XAMPP/xamppfiles/htdocs
mkdir yii2-myextension
cd yii2-myextension
composer init

Follow the interactive wizard. I use Atom, and I would open a new Atom editor window, then "File > Add Project Folder" and select "yii2-myextension" to open the whole directory to work in. Now, we will only have "composer.json" in here so far. Open it.

You will notice that "init" automatically created a basic composer file. Here is mine, excluding keywords, description, etc. because those don't really matter.

{
    "name": "wadeshuler/yii2-myextension",
    "type": "yii2-extension",
    "minimum-stability": "dev",
    "autoload": {
        "psr-4": {
            "wadeshuler\\myextension\\": ""
        }
    }
}

Name: The name is /yii2-. 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. Right now, there is nothing but "composer.json" in our directory.

We need to load our extension into our Yii2 app. 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! No committing, no updating. Just edit, save, refresh!!!

When you are done and your extension is perfect, you can then put it under version control, push it to GitHub and Packagist. Then you remove the "repositories" section so it no longer links to your local directory, and edit the "require-dev" just like adding anything else from Packagist. How to add your Packagist package is beyond the scope of this tutorial. However, the gist is, you must make a "release" in GitHub in order for Packagist to work.

Ok, so now your extension is great, however there is a bug you need to fix and you want to add a new feature.. Here is what I would do.

We don't need to commit or update for this either. Revert your "composer.json" back to how I showed above, so you are "live editing" again. If you lost your project, you could "git clone" it back into your "htdocs". You can combine live editing and with your GitHub workflow. You can create a branch, live edit your files, and commit when ready. This is possible because when you switch the branch, the files are actually swapped instantly. So the file has your code, even if you haven't committed it yet! We aren't relying on any VCS, just the files like the good ole days.

Once you fixed your repo and have committed the changes, push it back to GitHub.