Commit b6630078 by Qiang Xue

Finished extension and third-party lib usage guide [skip ci]

parent fb299e92
......@@ -157,17 +157,6 @@ Testing
* [Fixtures](test-fixtures.md)
Extending Yii
-------------
* [Creating Extensions](extend-creating-extensions.md)
* [Customizing Core Code](extend-customizing-core.md)
* [Using 3rd-Party Libraries](extend-using-libs.md)
* **TBD** [Using Yii in 3rd-Party Systems](extend-embedding-in-others.md)
* **TBD** [Using Yii 1.1 and 2.0 Together](extend-using-v1-v2.md)
* [Using Composer](extend-using-composer.md)
Special Topics
--------------
......@@ -180,6 +169,7 @@ Special Topics
* [Performance Tuning](tutorial-performance-tuning.md)
* **TBD** [Shared Hosting Environment](tutorial-shared-hosting.md)
* [Template Engines](tutorial-template-engines.md)
* [Working with Third-Party Code](tutorial-yii-integration.md)
Widgets
......
Extending Yii
=============
> Note: This section is under development.
The Yii framework was designed to be easily extensible. Additional features can be added to your project and then reused, either by yourself on other projects or by sharing your work as a formal Yii extension.
Code style
----------
To be consistent with core Yii conventions, your extensions ought to adhere to certain coding styles:
- Use the [core framework code style](https://github.com/yiisoft/yii2/wiki/Core-framework-code-style).
- Document classes, methods and properties using [phpdoc](http://www.phpdoc.org/). - Extension classes should *not* be prefixed. Do not use the format `TbNavBar`, `EMyWidget`, etc.
> Note that you can use Markdown within your code for documentation purposes. With Markdown, you can link to properties and methods using the following syntax: `[[name()]]`, `[[namespace\MyClass::name()]]`.
### Namespace
Yii 2 relies upon namespaces to organize code. (Namespace support was added to PHP in version 5.3.) If you want to use namespaces within your extension,
- Do not use `yiisoft` anywhere in your namespaces.
- Do not use `\yii`, `\yii2` or `\yiisoft` as root namespaces.
- Namespaces should use the syntax `vendorName\uniqueName`.
Choosing a unique namespace is important to prevent name collisions, and also results in faster autoloading of classes. Examples of unique, consistent namepacing are:
- `samdark\wiki`
- `samdark\debugger`
- `samdark\googlemap`
Distribution
------------
Beyond the code itself, the entire extension distribution ought to have certain things.
There should be a `readme.md` file, written in English. This file should clearly describe what the extension does, its requirements, how to install it,
and to use it. The README should be written using Markdown. If you want to provide translated README files, name them as `readme_ru.md`
where `ru` is your language code (in this case, Russian).
It is a good idea to include some screenshots as part of the documentation, especially if your extension provides a widget.
It is recommended to host your extensions at [Github](https://github.com).
Extensions should also be registered at [Packagist](https://packagist.org) in order to be installable via Composer.
### Composer package name
Choose your extension's package name wisely, as you shouldn't change the package name later on. (Changing the name leads to losing the Composer stats, and makes it impossible for people to install the package by the old name.)
If your extension was made specifically for Yii2 (i.e. cannot be used as a standalone PHP library) it is recommended to
name it like the following:
```
yii2-my-extension-name-type
```
Where:
- `yii2-` is a prefix.
- The extension name is in all lowercase letters, with words separated by `-`.
- The `-type` postfix may be `widget`, `behavior`, `module` etc.
### Dependencies
Some extensions you develop may have their own dependencies, such as relying upon other extensions or third-party libraries. When dependencies exist, you should require them in your extension's `composer.json` file. Be certain to also use appropriate version constraints, eg. `1.*`, `@stable` for requirements.
Finally, when your extension is released in a stable version, double-check that its requirements do not include `dev` packages that do not have a `stable` release. In other words, the stable release of your extension should only rely upon stable dependencies.
### Versioning
As you maintain and upgrading your extension,
- Use the rules of [semantic versioning](http://semver.org).
- Use a consistent format for your repository tags, as they are treated as version strings by composer, eg. `0.2.4`,
`0.2.5`,`0.3.0`,`1.0.0`.
### composer.json
Yii2 uses Composer for installation, and extensions for Yii2 should as well. Towards that end,
- Use the type `yii2-extension` in `composer.json` file if your extension is Yii-specific.
- Do not use `yii` or `yii2` as the Composer vendor name.
- Do not use `yiisoft` in the Composer package name or the Composer vendor name.
If your extension classes reside directly in the repository root directory, you can use the PSR-4 autoloader in the following way in your `composer.json` file:
```json
{
"name": "myname/mywidget",
"description": "My widget is a cool widget that does everything",
"keywords": ["yii", "extension", "widget", "cool"],
"homepage": "https://github.com/myname/yii2-mywidget-widget",
"type": "yii2-extension",
"license": "BSD-3-Clause",
"authors": [
{
"name": "John Doe",
"email": "doe@example.com"
}
],
"require": {
"yiisoft/yii2": "*"
},
"autoload": {
"psr-4": {
"myname\\mywidget\\": ""
}
}
}
```
In the above, `myname/mywidget` is the package name that will be registered
at [Packagist](https://packagist.org). It is common for the package name to match your Github repository name.
Also, the `psr-4` autoloader is specified in the above, which maps the `myname\mywidget` namespace to the root directory where the classes reside.
More details on this syntax can be found in the [Composer documentation](http://getcomposer.org/doc/04-schema.md#autoload).
Working with database
---------------------
Extensions sometimes have to use their own database tables. In such a situation,
- If the extension creates or modifies the database schema, always use Yii migrations instead of SQL files or custom scripts.
- Migrations should be applicable to different database systems.
- Do not use Active Record models in your migrations.
Assets
------
- Register assets [through bundles](assets.md).
Events
------
TBD
i18n
----
- If extension outputs messages intended for end user these should be wrapped into `Yii::t()` in order to be translatable.
- Exceptions and other developer-oriented message should not be translated.
- Consider proving `config.php` for `yii message` command to simplify translation.
Testing your extension
----------------------
- Consider adding unit tests for PHPUnit.
Composer
========
> Note: This section is under development.
Yii2 uses Composer as its dependency management tool. Composer is a PHP utility that can automatically handle the installation of needed libraries and
extensions, thereby keeping those third-party resources up to date while absolving you of the need to manually manage the project's dependencies.
Installing Composer
-------------------
In order to install Composer, check the official guide for your operating system:
* [Linux](http://getcomposer.org/doc/00-intro.md#installation-nix)
* [Windows](http://getcomposer.org/doc/00-intro.md#installation-windows)
All of the details can be found in the guide, but you'll either download Composer directly from <http://getcomposer.org/>, or run the following command:
```
curl -s http://getcomposer.org/installer | php
```
We strongly recommend a global composer installation.
Installing Composer Class Autoloader
------------------------------------
Make sure the [entry script](concept-entry-scripts.md) of your application contains the following lines of code:
```php
// install Composer's class autoloader
require(__DIR__ . '/../vendor/autoload.php');
// include Yii class file
require(__DIR__ . '/../vendor/yiisoft/yii2/Yii.php');
```
Working with composer
---------------------
The act of [installing a Yii application](installation.md) with
```
composer.phar create-project --stability dev yiisoft/yii2-app-basic
```
creates a new root directory for your project along with the `composer.json` and `compoer.lock` file.
While the former lists the packages, which your application requires directly together with a version constraint, while the latter keeps track of all installed packages and their dependencies in a specific revision. Therefore the `composer.lock` file should also be [committed to your version control system](https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file).
These two files are strongly linked to the two composer commands `update` and `install`.
Usually, when working with your project, such as creating another copy for development or deployment, you will use
```
composer.phar install
```
to make sure you get exactly the same packages and versions as specified in `composer.lock`.
Only if want to intentionally update the packages in your project you should run
```
composer.phar update
```
As an example, packages on `dev-master` will constantly get new updates when you run `update`, while running `install` won't, unless you've pulled an update of the `composer.lock` file.
There are several parameters available to the above commands. Very commonly used ones are `--no-dev`, which would skip packages in the `require-dev` section and `--prefer-dist`, which downloads archives if available, instead of checking out repositories to your `vendor` folder.
> Composer commands must be executed within your Yii project's directory, where the `composer.json` file can be found.
Depending upon your operating system and setup, you may need to provide paths to the PHP executable and
to the `composer.phar` script.
Adding more packages to your project
------------------------------------
To add two new packages to your project run the follwing command:
```
composer.phar require "cebe/indent:>=1.0.2" "cebe/yii2-gravatar:>1.1"
```
This will resolve the dependencies and then update your `composer.json` file.
The above example says that a version greater than or equal to 1.0.3 of indent converter package
and version 1.1 or greater of gravatar extension are required.
For details of this syntax, see the [official Composer documentation](https://getcomposer.org/doc/01-basic-usage.md#package-versions).
The full list of available Composer-supported PHP packages can be found at [packagist](http://packagist.org/). You may also search packages interactively just by entering `composer.phar require`.
### Manually editing your version constraints
You may also edit the `composer.json` file manually. Within the `require` section, you specify the name and version of each required package, same as with the command above.
```json
{
"require": {
"michelf/php-markdown": ">=1.4",
"ezyang/htmlpurifier": ">=4.6.0"
}
}
```
Once you have edited the `composer.json`, you can invoke Composer to download the updated dependencies. Run
```
composer.phar update michelf/php-markdown ezyang/htmlpurifier
```
afterwards.
> Depending on the package additional configuration may be required (eg. you have to register a module in the config), but autoloading of the classes should be handled by composer.
Using a specific version of a package
------------------------------------
Yii always comes with the latest version of a required library that it is compatible with, but allows you to use an older version if you need to.
A good example for this is jQuery which has [dropped old IE browser support](http://jquery.com/browser-support/) in version 2.x.
When installing Yii via composer the installed jQuery version will be the latest 2.x release. When you want to use jQuery 1.10
because of IE browser support you can adjust your composer.json by requiring a specific version of jQuery like this:
```json
{
"require": {
...
"yiisoft/jquery": "1.10.*"
}
}
```
FAQ
---
### Getting "You must enable the openssl extension to download files via https"
If you're using WAMP check [this answer at StackOverflow](http://stackoverflow.com/a/14265815/1106908).
### Getting "Failed to clone <URL here>, git was not found, check that it is installed and in your Path env."
Either install git or try adding `--prefer-dist` to the end of `install` or `update` command.
### Should I Commit The Dependencies In My Vendor Directory?
Short answer: No. Long answer, see [here](https://getcomposer.org/doc/faqs/should-i-commit-the-dependencies-in-my-vendor-directory.md).
See also
--------
- [Official Composer documentation](http://getcomposer.org).
Using 3rd-Party Libraries
=========================
> Note: This section is under development.
Yii is carefully designed so that third-party libraries can be
easily integrated to further extend Yii's functionalities.
Using Packages Installed via Composer
-------------------------------------
Packages installed via Composer can be directly used in Yii without any special handling.
Using Downloaded Libraries
--------------------------
If a library has its own class autoloader, please follow its instruction on how to install the autoloader.
If a library does not have a class autoloader, you may face one of the following scenarios:
* The library requires specific PHP include path configuration.
* The library requires explicitly including one or several of its files.
* Neither of the above.
In the last scenario, the library is not written very well, but you can still do the following
work to make it work with Yii:
* Identify which classes the library contains.
* List the classes and the corresponding file paths in `Yii::$classMap`.
For example, if none of the classes in a library is namespaced, you may register the classes with Yii
like the following in the entry script after including `yii.php`:
```php
Yii::$classMap['Class1'] = 'path/to/Class1.php';
Yii::$classMap['Class2'] = 'path/to/Class2.php';
// ...
```
Using Yii in 3rd-Party Systems
------------------------------
Yii can also be used as a self-contained library to support developing and enhancing
existing 3rd-party systems, such as WordPress, Joomla, etc. To do so, include
the following code in the bootstrap code of the 3rd-party system:
```php
$yiiConfig = require(__DIR__ . '/../config/yii/web.php');
new yii\web\Application($yiiConfig); // No 'run()' invocation!
```
The above code is very similar to the bootstrap code used by a typical Yii application
except one thing: it does not call the `run()` method after creating the Web application
instance.
Now we can use most features offered by Yii when developing 3rd-party enhancements. For example,
we can use `Yii::$app` to access the application instance; we can use the database features
such as ActiveRecord; we can use the model and validation feature; and so on.
Using Yii2 with Yii1
--------------------
Yii2 can be used along with Yii1 at the same project.
Since Yii2 uses namespaced class names they will not conflict with any class from Yii1.
However there is single class, which name is used both in Yii1 and Yii2, it named 'Yii'.
In order to use both Yii1 and Yii2 you need to resolve this collision.
To do so you need to define your own 'Yii' class, which will combine content of 'Yii' from 1.x
and 'Yii' from 2.x.
When using composer you add the following to your composer.json in order to add both versions of yii to your project:
```json
"require": {
"yiisoft/yii": "*",
"yiisoft/yii2": "*",
},
```
Start from defining your own descendant of [[yii\BaseYii]]:
```php
$yii2path = '/path/to/yii2';
require($yii2path . '/BaseYii.php');
class Yii extends \yii\BaseYii
{
}
Yii::$classMap = include($yii2path . '/classes.php');
```
Now we have a class, which suites Yii2, but causes fatal errors for Yii1.
So, first of all, we need to include `YiiBase` of Yii1 source code to our 'Yii' class
definition file:
```php
$yii2path = '/path/to/yii2';
require($yii2path . '/BaseYii.php'); // Yii 2.x
$yii1path = '/path/to/yii1';
require($yii1path . '/YiiBase.php'); // Yii 1.x
class Yii extends \yii\BaseYii
{
}
Yii::$classMap = include($yii2path . '/classes.php');
```
Using this, defines all necessary constants and autoloader of Yii1.
Now we need to add all fields and methods from `YiiBase` of Yii1 to our 'Yii' class.
Unfortunately, there is no way to do so but copy-paste:
```php
$yii2path = '/path/to/yii2';
require($yii2path . '/BaseYii.php');
$yii1path = '/path/to/yii1';
require($yii1path . '/YiiBase.php');
class Yii extends \yii\BaseYii
{
public static $classMap = [];
public static $enableIncludePath = true;
private static $_aliases = ['system'=>YII_PATH,'zii'=>YII_ZII_PATH];
private static $_imports = [];
private static $_includePaths;
private static $_app;
private static $_logger;
public static function getVersion()
{
return '1.1.15-dev';
}
public static function createWebApplication($config=null)
{
return self::createApplication('CWebApplication',$config);
}
public static function app()
{
return self::$_app;
}
// Rest of \YiiBase internal code placed here
...
}
Yii::$classMap = include($yii2path . '/classes.php');
Yii::registerAutoloader(['Yii', 'autoload']); // Register Yii2 autoloader via Yii1
```
Note: while copying methods you should NOT copy method "autoload()"!
Also you may avoid copying "log()", "trace()", "beginProfile()", "endProfile()"
in case you want to use Yii2 logging instead of Yii1 one.
Now we have 'Yii' class, which suites both Yii 1.x and Yii 2.x.
So bootstrap code used by your application will looks like following:
```php
require(__DIR__ . '/../components/my/Yii.php'); // include created 'Yii' class
$yii2Config = require(__DIR__ . '/../config/yii2/web.php');
new yii\web\Application($yii2Config); // create Yii 2.x application
$yii1Config = require(__DIR__ . '/../config/yii1/main.php');
Yii::createWebApplication($yii1Config)->run(); // create Yii 1.x application
```
Then in any part of your program ```Yii::$app``` refers to Yii 2.x application,
while ```Yii::app()``` refers to Yii 1.x application:
```php
echo get_class(Yii::app()); // outputs 'CWebApplication'
echo get_class(Yii::$app); // outputs 'yii\web\Application'
```
Working with Third-Party Code
=============================
From time to time, you may need to use some third-party code in your Yii applications. Or you may want to
use Yii as a library in some third-party systems. In this section, we will show how to achieve these goals.
## Using Third-Party Libraries in Yii <a name="using-libs-in-yii"></a>
To use a third-party library in a Yii application, you mainly need to make sure the classes in the library
are properly included or can be autoloaded.
### Using Composer Packages <a name="using-composer-packages"></a>
Many third-party libraries are released in terms of [Composer](https://getcomposer.org/) packages.
You can install such libraries by taking the following two simple steps:
1. modify the `composer.json` file of your application and specify which Composer packages you want to install.
2. run `php composer.phar install` to install the specified packages.
The classes in the installed Composer packages can be autoloaded using the Composer autoloader. Make sure
the [entry script](structure-entry-scripts.md) of your application contains the following lines to install
the Composer autoloader:
```php
// install Composer autoloader
require(__DIR__ . '/../vendor/autoload.php');
// include Yii class file
require(__DIR__ . '/../vendor/yiisoft/yii2/Yii.php');
```
### Using Downloaded Libraries <a name="using-downloaded-libs"></a>
If a library is not released as a Composer package, you should follow its installation instructions to install it.
In most cases, you will need to download a release file manually and unpack it in the `BasePath/vendor` directory,
where `BasePath` represents the [base path](structure-applications.md#basePath) of your application.
If a library carries its own class autoloader, you may install it in the [entry script](structure-entry-scripts.md)
of your application. It is recommended the installation is done before you include the `Yii.php` file so that
the Yii class autoloader can take precedence in autoloading classes.
If a library does not provide a class autoloader, but its class naming follows [PSR-4](http://www.php-fig.org/psr/psr-4/),
you may use the Yii class autoloader to autoload the classes. All you need to do is just to declare a
[root alias](concept-aliases.md#defining-aliases) for each root namespace used in its classes. For example,
assume you have installed a library in the directory `vendor/foo/bar`, and the library classes are under
the `xyz` root namespace. You can include the following code in your application configuration:
```php
[
'aliases' => [
'@xyz' => '@vendor/foo/bar',
],
]
```
If neither of the above is the case, it is likely that the library relies on PHP include path configuration to
correctly locate and include class files. Simply follow its instruction on how to configure the PHP include path.
In the worst case when the library requires explicitly including every class file, you can use the following method
to include the classes on demand:
* Identify which classes the library contains.
* List the classes and the corresponding file paths in `Yii::$classMap` in the [entry script](structure-entry-scripts.md)
of the application. For example,
```php
Yii::$classMap['Class1'] = 'path/to/Class1.php';
Yii::$classMap['Class2'] = 'path/to/Class2.php';
```
## Using Yii in Third-Party Systems <a name="using-yii-in-others"></a>
Because Yii provides many excellent features, sometimes you may want to use some of its features to support
developing or enhancing 3rd-party systems, such as WordPress, Joomla, or applications developed using other PHP
frameworks. For example, you may want to use the [[yii\helpers\ArrayHelper]] class or use the
[Active Record](db-active-record.md) feature in a third-party system. To achieve this goal, you mainly need to
take two steps: install Yii, and bootstrap Yii.
If the third-party system uses Composer to manage its dependencies, you can simply run the following commands
to install Yii:
```
php composer.phar require yiisoft/yii2-framework:*
php composer.phar install
```
Otherwise, you can [download](http://www.yiiframework.com/download/) the Yii release file and unpack it in
the `BasePath/vendor` directory.
Next, you should modify the entry script of the 3rd-party system by including the following code at the beginning:
```php
require(__DIR__ . '/../vendor/yiisoft/yii2/Yii.php');
$yiiConfig = require(__DIR__ . '/../config/yii/web.php');
new yii\web\Application($yiiConfig); // Do NOT call run() here
```
As you can see, the code above is very similar to that in the [entry script](structure-entry-scripts.md) of
a typical Yii application. The only difference is that after the application instance is created, the `run()` method
is not called. This is because by calling `run()`, Yii will take over the control of the request handling workflow.
Like in a Yii application, you should configure the application instance based on the environment running
the third-party system. For example, to use the [Active Record](db-active-record.md) feature, you need to configure
the `db` application component with the DB connection setting used by the third-party system.
Now you can use most features provided by Yii. For example, you can create Active Record classes and use them
to work with databases.
## Using Yii 2 with Yii 1 <a name="using-both-yii2-yii1"></a>
If you were using Yii 1 previously, it is likely you have a running Yii 1 application. Instead of rewriting
the whole application in Yii 2, you may just want to enhance it using some of the features only available in Yii 2.
This can be achieved as described below.
> Note: Yii 2 requires PHP 5.4 or above. You should make sure that both your server and the existing application
support this.
First, install Yii 2 in your existing application by following the instructions given in the last subsection.
Second, modify the entry script of the application as follows,
```php
// include the customized Yii class described below
require(__DIR__ . '/../components/Yii.php');
// configuration for Yii 2 application
$yii2Config = require(__DIR__ . '/../config/yii2/web.php');
new yii\web\Application($yii2Config); // Do NOT call run()
// configuration for Yii 1 application
$yii1Config = require(__DIR__ . '/../config/yii1/main.php');
Yii::createWebApplication($yii1Config)->run();
```
Because both Yii 1 and Yii 2 have the `Yii` class, you should create a customized version to combine them.
The above code includes the customized `Yii` class file, which can be created as follows.
```php
$yii2path = '/path/to/yii2';
require($yii2path . '/BaseYii.php'); // Yii 2.x
$yii1path = '/path/to/yii1';
require($yii1path . '/YiiBase.php'); // Yii 1.x
class Yii extends \yii\BaseYii
{
// copy-paste the code in YiiBase (1.x) here
}
Yii::$classMap = include($yii2path . '/classes.php');
// register Yii2 autoloader via Yii1
Yii::registerAutoloader(['Yii', 'autoload']);
```
That's all! Now in any part of your code, you can use `Yii::$app` to access the Yii 2 application instance, while
`Yii::app()` will give you the Yii 1 application instance:
```php
echo get_class(Yii::app()); // outputs 'CWebApplication'
echo get_class(Yii::$app); // outputs 'yii\web\Application'
```
......@@ -24,7 +24,7 @@ structure-modules.md | Yes
structure-filters.md | Yes
structure-widgets.md | Yes
structure-assets.md |
structure-extensions.md |
structure-extensions.md | Yes
runtime-bootstrapping.md |
runtime-routing.md |
runtime-requests.md |
......@@ -87,12 +87,6 @@ test-unit.md |
test-functional.md |
test-acceptance.md |
test-fixtures.md |
extend-creating-extensions.md |
extend-customizing-core.md |
extend-using-libs.md |
extend-embedding-in-others.md |
extend-using-v1-v2.md |
extend-using-composer.md |
tutorial-advanced-app.md |
tutorial-start-from-scratch.md |
tutorial-console.md |
......@@ -102,6 +96,7 @@ tutorial-performance-tuning.md |
tutorial-shared-hosting.md |
tutorial-template-engines.md |
tutorial-core-validators.md | Yes
tutorial-yii-integration.md | Yes
widget-bootstrap.md |
widget-jui.md |
helper-overview.md |
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment