How to use composer with my Yii application - php

I have developed web app using Yii 1.1.3, and I am very much new with Core php, can anyone give me some detail that how I can use composer with Yii app.
I have used Bootstrap, RESTFull Yii, yii-user and some other extensions.
Your help will be appreciated.

I am assuming that you know how to create your composer.json and so on?
If so then you use Composer with Yii as you would with any other application.
You just have to modify Yii's classMap to make sure it picks up the loaded composer requirements.
Edit your index.php (and probably also your yiic.php in the protected folder if you have one) and load the Composer autoloader and pass the map onto Yii:
$loader = require(__DIR__ . '/../vendor/autoload.php');
Yii::$classMap = $loader->getClassMap();
It is possible you have to modify the include path of course (my example assumes you have a public_html-folder.
If you also want to add your application classes to the map, so that you don't have to add aliases all the time:
"autoload": {
"classmap": [
"protected/"
],
Don't forget to run composer dump-autoload after you add classes then or it won't find them.

Related

How to use one module in two different application/project in yii2

I have module created in the basic project of yii2 and now i want to access or use that module another project/application of mine....
How can I achieve this.
please help me out here.
To use module in different apps there are 3 things you need.
The module must not be dependent on classes from core project. For any class that needs to be implemented by core project the module should define interface and depend on that interface instead of class itself.
The module should use different namespace than app and autoloader must know how to load classes from that namespace. (more about that later)
You have to add module in your config in same way you've added it in first project.
The points 1 and 3 are pretty much self-explaining. If are not sure how to add module in config see the yii2 guide.
Now back to the second point. While naive way of copying module over to second project would work it will turn maintaining the module into nightmare because each change would have to be done in each copy of module. So it's better to keep the code of module in one place and make it available for each project. There are multiple ways of doing that.
If you want to, you can turn your module into extension and make it publicly available through packagist as it was suggested by M. Eriksson in comments. After that you would simply add your extension through composer as any other dependency.
Composer also allows you to define and use private repositories if you don't want to publish your module at packagist. See composer documentation for more details.
The most trivial way is to simply put the code into separate folder outside of project. If you do that, you have to make sure that autoloaders in your projects are capable of finding the files locations to load classes. There are two options how to do that. In any case you will want to avoid conflicts with namespaces used by your project, that's why you need to use different namespace.
Let's assume that you've put your module files into folder /path/to/modules/myModule and all classes in your module belongs to namespace modules\myModule. You have to make sure that your webserver can access that folder and that it can run php scripts there.
First option is to use Yii's autoloader. That autoloader uses aliases to look for classes. If you add #modules alias and point it to /path/to/modules folder, the Yii autoloader will try to look for any class from modules\* namespace in /path/to/modules folder. You can add the alias in your config file (web.php, console.php or any other config file you use):
return [
// ...
'aliases' => [
'#modules' => '/path/to/modules',
// ... other aliases ...
],
];
The second option is to use project's composer.json file to set autoloader generated by composer to load your classes.
{
"autoload": {
"psr-4": {
"modules\\": "/path/to/modules"
}
}
}
You can find more info about this in composer's documentation.
Don't forget to run composer dump-autoload after you change autoload settings in your composer.json file to update the generated autoloader.

Composer, autoloading & class calling after autoloading

I was wondering, I am currently trying to change my programming style to work with composer and its package system (my god why didn't I use it sooner?) but I was wondering I am trying to work following the PSR-4 standard.
And got the following php file
<?php
require_once(__DIR__ . '/vendor/autoload.php');
$class = new vendorname\packagename\classname;
$example = new vendorname\packagename\subpackage\classname2;
Is that good practice to use with composer and the PSR-4 standard?
Where the the classes are existing in:
- /vendor
-- /vendorname
--- /packagename
--- /src
---- classname.php
---- /subpackage
----- classname2.php
I am currently thinking it is, but I just want to make sure that I am using it correctly according to the PSR-4 standard :-).
Typically that is the way to go, but some packages use different namespaces (mainly packages that need to have legacy support, for as far as I have encountered). Therefore after you composer require the package and it's installed, you should check the files for the namespaces that are used. But yes, you are right, because the way you say it is how it's typically done.
Also usually the package's readme/website has some examples on how to construct their objects.
Example: The Monolog logger package has a file /vendor/monolog/monolog/src/Monolog/Logger.php that is in the Monolog namespace, not in the Monolog\Monolog\Src\Monolog namespace. Just be sure to check it, but most of the times examples on the package maintainer/owner's website will tell you how to use the package. In this example the readme on Github tells you how the package is used.
Most of packages include readme referring it's namespace. you can access classes using that namespace. if you can't found you can check from 'your_project_root/vendor/vendor_name/package_name/composer.json'.
"autoload": {
"psr-4": {"Monolog\\": "src/Monolog"}
},
For this example 'Monolog' is the namespace and this is the best way to follow psr standards.
<?php
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
// create a log channel
$log = new Logger('name');
$log->pushHandler(new StreamHandler('path/to/your.log', Logger::WARNING));
// add records to the log
$log->warning('Foo');
$log->error('Bar');
You can see all this standards in https://www.php-fig.org/psr/
Additionally you can check how this packages loaded in 'autoload_psr4.php' located in
'your_project_root/vendor/composer/autoload_psr4.php'
when you run composer require, composer update or composer dump-autoload command. this file will updated.

How to check if composer's autoloader is being used?

I'm developing a certain PHP framework for WordPress, and I want to give my users the option to use composer to install it as a package, or to install it manually. If composer is used, then a psr-4 class autoloader handles everything. If not, then all files must be loaded manually during the framework's bootstrapping process.
Is there a safe way to check whether composer's autoloader is being used in a given WordPress environment?
Currently i'm using:
if( !class_exists('Composer\\Autoload\\ClassLoader') )
{
// Manually include files if composer is not used.
require_once 'some/files.php';
}
However, if in a given WordPress environment there is a plugin that uses composer internally, then the above if statement will return true even though other plugins have no access to it.
The solution, as it turns out, is quite simple. You need to create 2 different bootstrapping files, say manual-bootstrap.php and composer-bootstrap.php. Then add the following lines to composer.json:
"autoload": {
"files": ["composer-bootstrap.php"]
}
composer-bootstrap.php will only be called if composer is used to load the framework as a dependency. Users that want to load the framework manually will use manual-bootstrap.php instead.
if(class_exists("\Composer\Autoload\ClassLoader"))
{
// a composer autoload.php has already been included/required
}

How to autoload multiple classes in Yii extension?

I am not sure whether title of question is exactly what I want to ask.
I want to use Authorize.net in my Yii application. Authorize.net has an API consisting of multiple classes and in order for the API to work all the classes should be autoloaded. In its SDK there is one file named autoload.php that does that. Please note that autoload.php is NOT a class, it just contains a function. Here is its code:
spl_autoload_register(function($className) {
static $classMap;
if (!isset($classMap)) {
$classMap = require __DIR__ . DIRECTORY_SEPARATOR . 'classmap.php';
}
if (isset($classMap[$className])) {
include $classMap[$className];
}
});
By requiring this file in my code I can do work with API successfully. Like:
require 'sdk-php-master/autoload.php
//I can make successful API calls after requiring autoload.php to be loaded.
But now the problem is I want to make same API work in Yii. I placed the SDK folder in extensions directory. Now I need to set extension path to be able to use it in my application. Now the problem is what should I set in class name for in config.php to make it work?
I tried this:
'authorize' => array(
'class' => 'application.extensions.authorize.autoload',
),
But that does not work, and it should not since autoload.php is not a class. All the necessary classes that should be autoloaded are placed in application.extensions.authorize.lib directory. How should I autoload all of them in Yii since according to my knowledge we can only have one entry in config.php for class.
Here is the link to SDK and its directory structure. Authorize.net SDK
This library uses composer, i recommend to you to use composer in your project to manage your libraries, and you will have no hassle with autloads.
Basicly create composer.json in your root project directory and place authorize part in it (and any further things)
{
"require": {
"authorizenet/authorizenet": "~1.8"
}
}
In your main index.php place:
require '/path/to/vendor/autoload.php';
somewhere before require $yii
Then call composer install. This in in short, for more details about composer this guide should be fine.
Update:
Composer will greatly improve your workflow when your require some external libraries. However if you really don't wan't to use composer, then just require autoload.php in index.php
Then use this library classes as in docs. Do not configure it as extension - this library is not Yii specific. In any code part just use it, for example:
define("AUTHORIZENET_API_LOGIN_ID", "YOURLOGIN");
define("AUTHORIZENET_TRANSACTION_KEY", "YOURKEY");
$subscription = new AuthorizeNet_Subscription;
$subscription->name = "PHP Monthly Magazine";
...
I found the solution to this. I just imported all the required folders in config main.php like this:
'import' => array(
'application.extensions.*',
'application.models.*',
'application.components.*',
'application.extensions.authorize.*',
'application.extensions.authorize.lib.*',
'application.extensions.authorize.lib.shared.*',
),
You can autoload all Authorize.net files using the following code on your protected/config/main.php file:
Yii::setPathOfAlias('Authorize', dirname(__FILE__).'/../extensions/sdk-php-master');
Yii::import('Authorize.autoload', true);

Own project via composer

I've got some libraries loaded through composer, and I'm wondering if it's possible to add my own library in the /vendor map, and then to have the composer autoloader load it? The structure would be something like /vendor/mylibrary/ and then a namespace mylibrary.
Would this be possible? Also would it be possible to add a different map to the composer autoloader? Like for example /app/src/ and then to have it load all the classes in that folder? Or do I have to make my own loader for that?
Thanks
Reading the composer documentation:
You can even add your own code to the autoloader by adding an autoload field to composer.json.
{
"autoload": {
"psr-0": {"Acme": "src/"}
}
}
Composer will register a PSR-0 autoloader for the Acme namespace.
You define a mapping from namespaces to directories. The src directory would be in your project root, on the same level as vendor directory is. An example filename would be src/Acme/Foo.php containing an Acme\Foo class.
After adding the autoload field, you have to re-run install to
re-generate the vendor/autoload.php file.
So basically, you just need to follow PSR-0, and tell composer where to find your library, by adding that line to your composer.json
Yes.You can achieve it. Configure your composer.json file as following:
{
"autoload": {
"classmap": [ "classes" ]
}
Here classes is the name of the directory where you have all your application related classes.Vendor related class should be auto detected as well. Just add the following line to achieve both at the same time:
require 'vendor/autoload.php';
And you can use the namesapce to reference your class like the following:
use classes\Model\Article;
Yes, of course it is possible to add own libraries and you should feel highly encouraged to do so. If your library is available publicly, you can simply register it at packagist.org. If not, it's a bit more complicated, but not impossible.
If your project does not follow the PSR-0 standard, composer will create a classmap for you. A custom autoloader is not supported.
I'd recommend you to read the (really excellent) documentation about all this and come back, if you're running into problems.
http://getcomposer.org/doc/

Categories