CodeIgniter Forums
how to use composer when application and system directory are not in webroot? - Printable Version

+- CodeIgniter Forums (https://forum.codeigniter.com)
+-- Forum: Using CodeIgniter (https://forum.codeigniter.com/forum-5.html)
+--- Forum: Best Practices (https://forum.codeigniter.com/forum-12.html)
+--- Thread: how to use composer when application and system directory are not in webroot? (/thread-74805.html)



how to use composer when application and system directory are not in webroot? - sneakyimp - 11-08-2019

I'm not a big fan of composer, nor am I especially well-versed in its use, but I have need of some code libraries/sdks that insist on using composer to install them.

In the interest of security, I have set up my CodeIgniter projects so that the application and system directories are NOT inside the webroot. I.e., my whole project is in:
/var/www/project

My web root is:
/var/www/project/html

My application and system directories are:
/var/www/project/application
/var/www/project/system


It is my understanding that setting codeigniter's composer_autoload configuration setting to TRUE will cause CodeIgniter to try and find Composer's autoload.php file in application/vendor. However, you can see that the default CodeIgniter directory structure has a composer.json file in the project's root.

What is the official word on using composer to install supporting code libraries (e.g., sendgrid/sendgrid, google/cloud-vision) to use in my codeigniter project? Do we install these in a vendor folder at the root of our project? Or do we install them in the application/vendor folder where CodeIgniter expects them to be fore composer_autload=TRUE? If we put the vendor folder inside the application folder, won't that mean that the composer.json, composer.lock, composer.phar files will also live in the application folder? Is this secure and/or desirable? Won't we then have a composer.json in the project root (the one linked above) and also a different one in the application folder? Seems a bit confusing.

And I'd point out that if we choose instead to install these packages in the vendor folder at the top level of our project (/var/www/project) in my case that CodeIgniter defines no constant for this directory. CI defines APPPATH, BASEPATH, FCPATH, and VIEWPATH but does not define any constant for the parent directory of the application and system folders. This doesn't present a huge obstacle if one chooses to eschew composer_autoload in favor of on-demand loading, but one must either require autoload.php by referring to some hard-wired path to this file (which breaks if you move your project), define a new constant for one's project root directory relative to some other directory constant, or do something like this:
Code:
require dirname(APPPATH) . "/vendor/autoload.php";

What is the best practice for use of third party libraries installed via composer? I'd love to know what is recommended and what the tradeoffs might be.


RE: how to use composer when application and system directory are not in webroot? - dave friend - 11-08-2019

Assuming you want vendor/ at the same level as application/ then, using the example code below, adjusting for some other file structure is automatic as long as vendor/ and application/ retain the same relationship in the file hierarchy

PHP Code:
$config['composer_autoload'] = str_replace('application/''vendor/'APPATH); 

If you're going with vendor/ inside application/ then do this.

PHP Code:
$config['composer_autoload'] = APPATH 'vendor/'

There is no advantage or disadvantage I can think of for having them one place or the other, but I agree it is best to have both outside the public space.


RE: how to use composer when application and system directory are not in webroot? - sneakyimp - 11-10-2019

(11-08-2019, 02:03 PM)dave friend Wrote: Assuming you want vendor/ at the same level as application/ then, using the example code below, adjusting for some other file structure is automatic as long as vendor/ and application/ retain the same relationship in the file hierarchy
Might this introduce any problems with composer? I'd point out that any composer changes, such as installing the packages I described in my OP, would be making adjustments to the composer.json file that exists as part of the basic CodeIgniter install. I worry that this might introduce problems.

(11-08-2019, 02:03 PM)dave friend Wrote:
PHP Code:
$config['composer_autoload'] = str_replace('application/''vendor/'APPATH); 
I would point out that this would be problematic if my project had "application/" in its path already. E.g., if my project were called "my-application" instead of "project" and was installed at /var/www/my-application/.

(11-08-2019, 02:03 PM)dave friend Wrote:
PHP Code:
$config['composer_autoload'] = APPATH 'vendor/'
That path, if I'm not mistaken, is where CodeIgniter assumes your autoload file is by default. You could just set it to TRUE and CodeIgniter would look in that spot for the autoload file. This is partly what prompted my question in the first place. If CodeIgniter by default looks for the autoload file at application/vendor/autoload.php, perhaps there is some compelling reason for that location to be used?

Also, I prefer *not* to use the autoload feature myself because the vast majority of controller methods I've defined have no need for the libraries I'm installing using composer. There's no point in loading composer's autoloader for the vast majority of pages on my site. For this reason, I prefer to only load the autoloader manually when the libraries are needed like so:
PHP Code:
require_once APPPATH "vendor/autoload.php"
It's still a bit disappointing that I must autoload ALL my composer-installed libraries at once rather than just loading the one I need at a given time. It seems a bit inefficient. I pretty much never need to use sendgrid and google vision SDKs at the same time.


RE: how to use composer when application and system directory are not in webroot? - dave friend - 11-10-2019

My first answer was aimed only at handling your very valid concern about "hard-wired" paths. Now I'll talk about the rest of your OP.

IMO, the design assumption that /vendor should be in /application was incorrect. It is common, dare I say a universal industry practice to install Composer locally in the project folder e.g. /var/www/project. The Composer documentation itself makes this recommendation. That directory is also the place that composer.json is expected to be.

By default, Composer creates /vendor in the project directory.  You can configure Composer to put /vendor somewhere else, but CodeIgniter does not do that. If it did you would see something like the following in the distributed composer.json.

Code:
"config": {
    "vendor-dir": "application/vendor"
}

But you don't see that. I have no idea why CI "thinks" the way it does.

So, it's my recommendation to go with standard industry practice. Install Composer to and run it from the project directory and let /vendor be created there too.

(11-10-2019, 09:28 AM)sneakyimp Wrote: Might this introduce any problems with composer? I'd point out that any composer changes, such as installing the packages I described in my OP, would be making adjustments to the composer.json file that exists as part of the basic CodeIgniter install. I worry that this might introduce problems.
I cannot think of what those problems might be. The distributed composer.json file only installs a couple of packages that are useful for developing applications, but none that CodeIgniter itself depends on.
As long as you use Composer to manage the packages it's pretty hard to mess it up. That includes accidentally deleting or replacing composer.json. Just don't loose composer.lock which is a file that should be tracked in git or whatever tool you use for version control.

(11-10-2019, 09:28 AM)sneakyimp Wrote:
(11-08-2019, 02:03 PM)dave friend Wrote:
PHP Code:
$config['composer_autoload'] = str_replace('application/''vendor/'APPATH); 
I would point out that this would be problematic if my project had "application/" in its path already. E.g., if my project were called "my-application" instead of "project" and was installed at /var/www/my-application/.
Yes, that's true. But for solving the problem you defined in the OP it works.

(11-10-2019, 09:28 AM)sneakyimp Wrote:
(11-08-2019, 02:03 PM)dave friend Wrote:
PHP Code:
$config['composer_autoload'] = APPATH 'vendor/'
That path, if I'm not mistaken, is where CodeIgniter assumes your autoload file is by default. You could just set it to TRUE and CodeIgniter would look in that spot for the autoload file. This is partly what prompted my question in the first place. If CodeIgniter by default looks for the autoload file at application/vendor/autoload.php, perhaps there is some compelling reason for that location to be used?
Again, you are correct. That is the path CodeIgniter assumes and simply using true would produce the same result. I lost track of that because; 1) I always put /vendor in the project directory; 2) I forgot that CodeIgniter expects a non-standard location for /vendor. I cannot find a compelling reason for that and, as pointed out earlier, several reasons why it's compelling for it to be in the project root.

(11-10-2019, 09:28 AM)sneakyimp Wrote: Also, I prefer *not* to use the autoload feature myself because the vast majority of controller methods I've defined have no need for the libraries I'm installing using composer. There's no point in loading composer's autoloader for the vast majority of pages on my site. For this reason, I prefer to only load the autoloader manually when the libraries are needed like so:
PHP Code:
require_once APPPATH "vendor/autoload.php"
It's still a bit disappointing that I must autoload ALL my composer-installed libraries at once rather than just loading the one I need at a given time. It seems a bit inefficient. I pretty much never need to use sendgrid and google vision SDKs at the same time.

I think you are confusing the CodeIgniter feature  “Auto-load” with the computer programming term "autoloading". In the context of Composer "autoload" refers to the capability of loading and linking code  automatically when needed, so that the programmer is not required to define or include those portions of the program explicitly. In other words, it eliminates the need write and maintain a lot of require and include statements.

The following code does not load all the composer installed libraries at once.

PHP Code:
require_once APPPATH "vendor/autoload.php"

What it does is put in place code that will find the appropriate class file and include (or require) it on demand. For instance, assume you have used Composer to install the "PhpSpreadsheet" package. To use this package in a controller you first need tell the class that you intend to use the class

PHP Code:
<?php
/**
 * Displays some report and export a spreadsheet
 */

use PhpOffice\PhpSpreadsheet\Writer\Xlsx;

defined('BASEPATH') OR exit('No direct script access allowed');

class 
Reports extends CI_Controller
{
... 

Then when you need to write to the excel file there isn't a call to $this->load->... or include('/path/to/class/file) or any extra lines of code. You simply create an instance like this

PHP Code:
$writer = new Xlsx($workbook); 

And the autoloader will find the file and include it automatically. But the code is not loaded until the call to new.

Just use $config['composer_autoload'] and forget about having to include autoload.php anywhere for the rest of your project lifetime.