Composer Autoload not working after deployment - php

I am in the midst of learning how to better maintain the code that I write. I have two projects that I am currently working on - both are in development and both are pushed to GitHub.
I am trying to include the one project in the other (by declaring it a dependency in the one project's composer.json file) - but after it is included, it is missing the proper autoload configurations.
I'll explain a little better: Project A's composer.json file has an autoload line for "psr-4" mapping the namespace to the "src" directory - all is good and working after I run:
composer install
I am then able to include the /vendor/autoload.php file and immediately start working with the project. When I look at the generated "autoload_psr4.php" file in that project's vendor directory, I can see the array contains a reference for the mapped namespace / directory per the composer.json file.
The problem comes when I try to include Project A within Project B as a dependency - everything looks to work after running the composer install - the vendor directory is created and the files are copied there - however when I look at the generated "autoload_psr4.php" file in project B it is missing the mapped namespace / directory per Project A's composer.json file.
Can someone point me in the direction for what I might be missing to get the autoload line to carry over into Project B?
Here's the two composer.json files:
Project A:
{
"name": "jfreynik/hydra-net",
"description": "Network classes for the Hydra framework.",
"type": "library",
"keywords": [ "http", "net", "rest" ],
"license": "MIT",
"require": {
"php": ">=5.3.0"
},
"autoload": {
"psr-4": {
"hydra\\net\\": "src/"
}
}
}
Project B:
{
"name": "jfreynik/simple-mvc",
"description": "A pretty simple MVC framework for building websites.",
"type": "framework",
"keywords": [ "MVC", "Website Framework" ],
"license": "MIT",
"repositories": [
{
"type":"package",
"package": {
"name": "jfreynik/hydra-net",
"version":"*-dev",
"source": {
"url": "https://github.com/jfreynik/hydra-net.git",
"type": "git",
"reference":"master"
}
}
}
],
"require": {
"jfreynik/hydra-net": "*-dev"
},
"minumum-stability": "dev"
}
Thank You!

The issue was that I was including Project A into Project B as a "package". I believe "packages" are not scanned for their contained composer.json files. (please correct me if I'm wrong) - by changing Project B's composer.json file to reference Project A as "vcs" then the autoloading works again. - Here is the adjusted composer.json file for Project B.
{
"name": "jfreynik/simple-mvc",
"description": "A pretty simple little MVC framework for building websites.",
"type": "framework",
"keywords": [ "MVC", "Website Framework" ],
"license": "MIT",
"repositories": [
{
"type":"vcs",
"url": "https://github.com/jfreynik/hydra-net"
}
],
"require": {
"jfreynik/hydra-net": "dev-master"
},
"minumum-stability": "dev"
}
I really had trouble finding working examples as I am really just starting to use composer and prior to this had only included professional packages from packagist. I have much to learn (even in regard to terminology) - so if anyone can add additional relevant information for the proper way to include 1 development project in another I will accept your answer.

Related

Setup a project with Composer by using custom repositories and packages

I am trying to setup a composer project that will enable me to setup my own framework and pulling out any given dependency stored in github private repos.
First some prerequisites:
I don't want to add code to packagist.
I want to make sure my vendor folder is as clean as possible.
Framework composer.json
{
"name": "mycompany/myframework",
"description": "YET another Framework",
"type": "project",
"repositories": [
{
"type": "package",
"package": {
"name": "mycompany/system",
"version": "0.0.2",
"type": "library",
"source": {
"url": "https://github.com/mycompany/system.git",
"type": "git",
"reference": "master"
}
}
}
],
"require": {
"mycompany/system": "0.0.2",
"mnsami/composer-custom-directory-installer": "1.1.*"
},
"license": "proprietary",
"authors": [...],
"extra":{
"installer-paths":{}
}
}
mycompany/system composer.json
{
"name": "mycompany/system",
"type": "library",
"description": "utility belt xD"
}
The code for the class in PHP ( from mycompany/sytem ) has the following structure:
namespace MYCOMPANY;
//this file name is called utils.php
//adherence to PSR-4 is assumed
class utils {
}
My goal is:
I want to tell composer that it should create the following structure :
vendor \ MYCOMPANY \ utils.php ( not vendor \ mycompany \system \utils.php )
Later on, I want to be able to add more repositories like this and store them under MYCOMPANY as well. The framwework will work around this setup.
Custom installation is handled by mnsami/composer-custom-directory-installer
I'm guessing I should keep, by rule of thumb, the different packages in their own directories, but, since there is no risk of overwriting because other files will have a different naming convention.
Edit
Can this be done?
If so, how?
Thank you in advance
After some hours of work and following on #NicoHaase's reply in the comments, I gave up on this issue.
I was trying to make a clean folder where I would put all the different classes from different repos, but composer just doesn't work that way.
I hope this will help others that want the same thing.

Composer does not respect installer-paths

Here is the scenario:
I have two projects driven by composer. The first one looks like this:
{
"name": "myusername/composer_test",
"description": "Composer project for CircleK Drupal 8",
"type": "project",
"license": "GPL-2.0-or-later",
"authors": [
{
"name": "Name Surname",
"role": "webdeveloper"
}
],
"repositories": [
{
"type": "composer",
"url": "https://packages.drupal.org/8"
}
],
"require": {
"php": ">=5.6",
"composer/installers": "^1.2",
"drupal-composer/drupal-scaffold": "^2.5",
"drupal/core": "^8.7.0",
"vlucas/phpdotenv": "^2.4",
"webflo/drupal-finder": "^1.0.0",
"webmozart/path-util": "^2.3",
"zaporylie/composer-drupal-optimizations": "^1.0"
},
"minimum-stability": "dev",
"prefer-stable": true,
"extra": {
"installer-paths": {
"web/core": ["type:drupal-core"]
}
}
}
Second one requires the first one and it's pretty straight forward:
{
"name": "user/site",
"description": "Composer for Site",
"type": "project",
"license": "GPL-2.0-or-later",
"authors": [
{
"name": "Name Surname",
"role": "webdeveloper"
}
],
"repositories": [
{
"type": "git",
"url": "git#github.com:myusername/composer_test.git"
},
{
"type": "composer",
"url": "https://packages.drupal.org/8"
}
],
"require": {
"myusername/composer_test": "dev-drupal_only"
},
"minimum-stability": "dev",
"prefer-stable": true
}
As you can see the first one defines where drupal core should be placed at by defining installer-paths. It turns out that when I run composer install just for the first composer.json file drupal core ends up in ./web directory as should, however when I run composer install for second file it does download every package from first composer.json just fine, but drupal core ends up in main directory instead of ./web. I know I can put installer-paths into the last composer file and overwrite it, but that's not the point. I want first file to define where stuff should be place at.
The extra settings only work for the root package. Consider user/site requiring 2 different packages that both specifiy different installer paths. Which one should composer use and how should it know? By ignoring those settings, unless they are specified in your root composer.json, composer circumvents any surprises/problems.
There is a way around this, you can create a post-install script that determines the correct path for you, e.g. by checking if myusername/composer_test is installed and the variable is set. This is a bit similar to how Symfony's Install-Script in the SensioDistributionBundle used to do it. It provides a fallback to determine the right directory to use based on configs and folder structure (due to changes in how the default directory structure looks at ~2.8, e.g. moving app/console to bin/console).
You could write your own install script that inspects the installed composer packages. The downside is, that just like you now have to specify the extra config in your second composer.json, you will have to specify the install scripts, plus you have to write the install script itself. So it might be a lot of extra work without gaining a lot from it.

Unable to use composer package in laravel

I am trying to use the following class in a laravel 5 project. https://packagist.org/packages/mk-j/php_xlsxwriter#dev-master
I do the:
composer require mk-j/php_xlsxwriter
Then it gets downloaded in my vendor folder. However I am unable to use it in a controller as it cannot find the class XLSXWriter.
I then look at the composer.json of mk-j/php_xlsxwriter and see the following:
{
"name": "mk-j/php_xlsxwriter",
"description": "PHP Library to write XLSX files",
"keywords": ["php", "library","xls", "xlsx", "excel"],
"type": "project",
"homepage": "https://github.com/mk-j/PHP_XLSXWriter",
"license": "MIT",
"autoload": {
"classmap": ["xlsxwriter.class.php"]
},
"require-dev": {
"phpunit/phpunit": "4.3.*"
}
}
It looks like the class is not PSR-4 compliant. Should I tweak the composer.json here to try to make it compliant but then that does not see adequate as another developer would have to do the same.
What can I do to be able to use the class in a controller? I am not very PSR savvy.
Thank You

Package Autoloading Issues

I'm struggling to work out how to correctly build and autoload my first composer package. I understand that if I follow the PSR-0 naming convention, autoloading should "just work". I am trying to set up with:
vendor: Programster
package name: CoreLibs
I have managed to debug a project that includes the package to the point where I am outputting the search path by putting a print in the findFileWithExtension() function of the ClassLoader.php file
/home/stuart/Desktop/test-project/vendor/Programster/CoreLibs/Programster/Programster/CoreLibs/Core.php
I know that the file is actually located at:
/home/stuart/Desktop/test-project/vendor/Programster/CoreLibs/Core.php
My Package's composer.json file:
{
"name": "Programster/CoreLibs",
"type": "library",
"description": "Core libraries for PHP 5.3+",
"keywords": ["core","library"],
"homepage": "http://svn.yadda-yadda.com/php/core-libs",
"license": "none",
"authors": [
{
"name": "xxxx",
"email": "my.email#email.com",
"homepage": "http://mywebsite.com/",
"role": "Developer"
}
],
"require": {
"php": ">=5.3.0"
},
"autoload": {
"psr-0": {
"Programster": "Programster"
}
}
}
The following is a tiny script in a project that includes the package to test if is working:
<?php
require_once(__DIR__ . '/../vendor/autoload.php');
$loader = new \Composer\Autoload\ClassLoader();
$loader->register();
use \Programster\CoreLibs as programster;
programster\Core::println("hello world");
The project's composer.json file to include the package:
{
"repositories": [ { "type": "composer", "url": "http://satis.mydomain.com/" } ],
"require": {
"Programster/CoreLibs": "dev-trunk"
}
}
Is my package's config wrong, or do I really need to create Programster/CoreLibs/ subdirectories within the CoreLibs repository source code?
use \Programster\CoreLibs as programster;
programster\Core::println("hello world");
Your class name evaluates to \Programster\CoreLibs\Core.
With this PSR-0 autoloading,
"psr-0": {
"Programster": "Programster"
}
the class name will be completely converted into a path name like "Programster/CoreLibs/Core.php", and this path will be searched inside the directory "Programster" relative to your libraries composer.json location.
Using PSR-4 autoloading,
"psr-4": {
"Programster\\CoreLibs\\": ""
}
the prefix in this definition will be removed from the classname, the remainder will be converted to a path (i.e. "Core.php") and be searched in the path mentioned (in this case, in the main directory of the library, because "" + "Core.php" is pointing to a file in without any sub directory).
Your second definition is better in some regards. It uses a longer prefix, which is relevant if you include more than one library using the same prefix, because then Composer would have to search more than one path to find the class. And it uses a shorter path, which also allows for slightly faster disk I/O operations (I haven't done any performance measurements, though).
I managed to get it working by using the PSR-4 standard that others suggested in the comments and updating my package's composer.json file (see the autoload section):
{
"name": "Programster/CoreLibs",
"type": "library",
"description": "Core libraries for PHP 5.3+",
"keywords": ["core","library"],
"homepage": "http://svn.mydomain/core-libs",
"license": "none",
"authors": [
{
"name": "MY name",
"email": "my.email#email.com",
"homepage": "http://my-website.com/",
"role": "Developer"
}
],
"require": {
"php": ">=5.3.0"
},
"autoload": {
"psr-4": {
"Programster\\CoreLibs\\": ""
}
}
}
This is my script in the project that has the package installed:
require_once(__DIR__ . '/../vendor/autoload.php');
\Programster\CoreLibs\Core::println("hello world");
#sectus was right, I did not need to use $loader = new \Composer\Autoload\ClassLoader();$loader->register();

Component-based development with composer

Let's say I want to write a new application.
/workspace/exampleapp/
.git
src/
vendor/
app/
component1/
.git
src/
composer.json
component2/
.git
src/
composer.json
composer.json
I have three git repositories. They have no remotes. I also have three composer.json files.
/workspace/app/composer.json
{
"name": "app/app",
"type": "project",
"license": "MIT",
"require": {
"app/component1": "dev-master",
"app/component2": "dev-master"
},
"autoload": {
"psr-4": {"app\\": "src/"}
}
}
/workspace/app/vendor/app/component1/composer.json
{
"name": "app/component1",
"type": "library",
"license": "MIT",
"autoload": {
"psr-4": {"app\\": "src/"}
}
}
/workspace/app/vendor/app/component2/composer.json
{
"name": "app/component2",
"type": "library",
"license": "MIT",
"autoload": {
"psr-4": {"app\\": "src/"}
}
}
If I run composer update in the project root I receive the error The requested package app/component1 could not be found in any version, there may be a typo in the package name.
What do I have to change to make it work? Is there a way without moving the components directories out of the vendor directory or creating remote repositories?
Thank you!
I think you are suffering from the XY problem - I'm going to pretend that you actually asked "How can I setup a project with Composer with the following requirements?"
Be able to work without a remote Git server i.e. be able to commit and push locally.
Be able to commit code for the components separately to the commits to the main project.
Be able to edit the code in the vendor directories for your repositories, and commit from those directories.
In which case the answer is, setup your directories like this:
/workspace/app/
composer.json
src/
/workspace/components/
component1/
composer.json
src/
component2/
src/
composer.json
Setup each of your component's composer file like this:
/workspace/components/component1/composer.json
{
"name": "app/component1",
"type": "library",
"license": "MIT",
"autoload": {
"psr-4": {"app\\": "src/"}
}
}
Tell your the composer.json file for your app to use the components directories as local git repositories.
/workspace/app/composer.json
{
"name": "app/app",
"type": "project",
"license": "MIT",
"require": {
"app/component1": "dev-master",
"app/component2": "dev-master"
},
"autoload": {
"psr-4": {"app\\": "src/"}
},
"repositories": [
{
"type": "vcs",
"url": "/workspace/components/component1"
},
{
"type": "vcs",
"url": "/workspace/components/component2"
}
],
}
When you do the first "composer update" you should run it with the option composer update --prefer-source. That will force composer to do a git clone for the code, rather than downloading just a zip-ball and extracting it.
(Adding --prefer-source may not be required, it seems composer may do clone by default when fetching from a local directory repository).
You will now be able to edit the code for the components in the vendor directory, be able to commit it separately to the app code, as well as be able to push it to 'remote' git repository at /workspace/components/component1/.

Categories