Composer Override a package file - php

I am trying to override a package file, as it doesn't work without modification and it hasn't been updated to fix this.
Package is webklex\laravel-pdfmerger and the file is PDFMerger.php
In it has:
use fpdi\FPDI;
for it to work correctly it needs to be:
use FPDI;
Obviously whenever I update using composer, this file is of course then incorrect, and at this stage I have to manually go in and change the file to get it working.
There must be a better way?
I've attempted making a copy of the git package, and then using composer to import it and attempt to override, composer snippet is below, but it doesn't do what I want it to do.
{
"name": "laravel/laravel",
"description": "The Laravel Framework.",
"keywords": ["framework", "laravel"],
"license": "MIT",
"type": "project",
"repositories": {
"laravel-pdfmerger": {
"type": "package",
"package": {
"name": "****/laravel-pdfmerger-mirror",
"version": "1.1.1",
"source": {
"url": "https://bitbucket.org/****/laravel-pdfmerger-mirror.git",
"type": "git",
"reference": "origin/master"
}
}
}
},
"require": {
...
"****/laravel-pdfmerger-mirror": "1.1.1",
"webklex/laravel-pdfmerger": "1.1"
},
"autoload": {
"classmap": [
"database"
],
"psr-4": {
"App\\": "app/",
"VendorExtensions\\xerolaravel\\": "packages/vendorExtensions/xerolaravel",
"Webklex\\PDFMerger\\PDFMerger\\": "vendor/****/laravel-pdfmerger-mirror/src/PDFMerger"
}
},
Any help here would be great.
--- EDIT ---
updated my composer.json file to remove the repository and change the psr-4 autoload to the following:
psr-4": {
"App\\": "app/",
"VendorExtensions\\xerolaravel\\": "packages/vendorExtensions/xerolaravel",
"Webklex\\laravel-pdfmerger\\PDFMerger\\": "vendor/webklex/laravel-pdfmerger/src/PDFMerger"
}
But it is still not overriding the original file whenever I do use PDFMerger. Is it because I'm using a Facade?

Figured this one out at last...
1) Import Forked respository in your composer.json file, but ensure the name matches the name of the package you are replacing; in my case webklex/laravel-pdfmerger, like so:
"repositories": {
"webklex/laravel-pdfmerger": {
"type": "package",
"package": {
"name": "webklex/laravel-pdfmerger",
"version": "1.1.1",
"source": {
"url": "url to git",
"type": "git",
"reference": "origin/master"
}
}
}
},
Note: Ensure you set a version higher than what is currently available on the original package, so here I added .1 to differentiate the change and tag the commit as this so I can select it.
2) require the package, but ensure you request the version you tagged in your commit:
"require": {
"php": ">=5.6.4",
"webklex/laravel-pdfmerger": "1.1.1"
},
3) Update the autoload to point to where the package has been imported:
"autoload": {
"classmap": [
"database"
],
"psr-4": {
"App\\": "app/",
"Webklex\\PDFMerger\\": "vendor/webklex/laravel-pdfmerger/src"
}
},
Run composer update and then dump the autoload.
You should then be able to reference the package in your application as per the instructions in the original package.

You can do this by putting your edited package in a vendor-custom directory and adding it to the autoload section of your composer.json.
"autoload": {
"psr-4": {
"App\\": "app/",
"Vendor\\Package": "vendor-custom/vendor/package"
}
},
Gregwar psr-0 example:
"autoload": {
"classmap": [
"database"
],
"psr-4": {
"App\\": "app/"
},
"psr-0": {
"Gregwar\\Cache": "vendor-custom/gregwar/cache",
"Gregwar\\Image": "vendor-custom/gregwar/image",
"Gregwar\\ImageBundle": "vendor-custom/gregwar/image-bundle"
}
},

In PHP, you can actually alias a class to another, and that behaviour include namespaces.
This is extremely useful in legacy projects where you want to start using namespaces but don't want to refactor all usage of the said class.
You have the opposite here, the class is defined in a namespace but the class you are using is not in a namespace, still, aliasing the class would do.
So the function you might be looking for is class_alias.
Here is an example
<?php
class FPDI {
public function __construct() {
var_dump('I am FPDI');
}
}
class_alias('FPDI', 'fpdi\FPDI');
$noNamespace = new FPDI; // would, off course work
$namespace = new fpdi\FPDI(); // would work too, thanks to the class alias
So if you are using Laravel, your job should be as simple as aliasing the class correctly.
This can actually be done where you define your providers and aliases.
So at the beginning of config/app.php
<?php
class_alias('FPDI', 'fpdi\FPDI');
return [
// all of the below array stays as you have it, it was just snipped for concision purpose
];

Related

How do I get my composer package autoloaded properly?

I have created a package to separate out business logic into easier to distribute modules. The composer file looks like this:
{
"name": "aggiq/johnny-cash",
"description": "A collection of controllers, models, migrations, and tests for a phonebanking backend.",
"license": "MIT",
"authors": [ ... ],
"require": {
"illuminate/database": ">=5.5"
},
"require-dev": {
"fzaninotto/faker": "~1.4"
},
"autoload": {
"psr-4": {
"Johnny\\Phonebanking\\": "src/"
}
}
}
And our source files are indeed in src/:
src/Controllers/PhonebankController.php
src/Models/Phonebank.php
...
I saved and pushed this to our gitlab repo, and then included it as a dependency in a test project:
{
...,
"repositories": [{
"type": "package",
"package": {
"name": "aggiq/johnny-cash",
"version": "0.1",
"type": "package",
"source": {
"url": "gitlab url",
"type": "git",
"reference": "dev"
}
}
}],
"require": {
"aggiq/johnny-cash": "*",
},
...
}
And when I do composer update, it successfully grabs the project and downloads it into the vendor folder:
vendor/aggiq/johnny-cash/Controllers/PhonebankController.php
...
However, when I look in the test project's autoload_psr4.php, it's not there. Is there a step I missed?
Edit: updates the directories to have capital letters to match the namespaces, and here is the generated PSR4 php file:
<?php
// autoload_psr4.php #generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
);
You have registered autoloading at your package's composer.json correctly:
"autoload": {
"psr-4": {
"Johnny\\Phonebanking\\": "src/"
}
}
This means, any class in Johnny\Phonebanking namespace will be in src directory. E.g.:
Johnny\Phonebanking\SomeClass => src/SomeClass.php
Johnny\Phonebanking\SomeNamespace\AnotherClass => src/SomeNamespace\AnotherClass.php
As you can see, it has to respect CapitalLetters.
Saying that, you should correct first letters of your directories, from:
src/controllers/PhonebankController.php
src/models/Phonebank.php
to
src/Controllers/PhonebankController.php
src/Models/Phonebank.php
I have solved it. We needed to do two things.
The repository type specified in the parent pacakge should be vcs not package since we are loading from a git server:
"repositories": [{
"type": "vcs",
"url": "git#xxx.git"
}]
The package type in the child package should be library:
"type": "library"
Once those two changes were made, composer update installed not only the child package but also its dependencies, proving it is being recognized by composer.

Class not being autoloaded

I've made a little library for myself and I'm trying to autoload it into my laravel project, it installs fine but whenever I try to use the class it simply says it's not found.
I've checked all the classmap files in vendor/composer and it doesn't seem to be in any of them.
This is my composer.json for my lib:
{
"name": "my-user/aspect-parser",
"version": "1.0.0",
"type": "package",
"require": {
"nesbot/carbon": "^1.22"
},
"autoload": {
"psr-4": {
"AspectParser\\": "src/"
}
}
}
My file structure is:
AspectParser
src
Parser.php
It was an issue with the type in composer.json. I've changed it to library and it adds to the autoload classmap.

How to autoload a repository in composer which does not follow PSR-0 or PSR-4?

So, I'm trying to use jcleblanc/reddit-php-sdk, but it follows no standards whatsoever and does not have a repository available, so I've had to manually define it myself in my composer.json file:
"repositories" : [{
"type": "package",
"package": {
"name": "jcleblanc/reddit-php-sdk",
"version": "dev-master",
"source": {
"url": "https://github.com/jcleblanc/reddit-php-sdk",
"type": "git",
"reference": "origin/master"
},
"autoload": {
"classmap": ["reddit-php-sdk/", "/", "reddit.php", "config.php"]
}
}
}],
Directory structure in vendor/ here:
However, when I then run composer dump-autoload, the classes in this project are not autoloaded, and don't appear in any of the autoload_*.php composer files. This means I of course get a "Class 'reddit' not found" error whenever I try and use it.
Solutions?
You can use Composer's file autoloading.
{
"autoload": {
"files": ["src/MyLibrary/functions.php"]
}
}
However, that's more geared towards helper function files and I've not tried it with a Class file (although there's no reason it shouldn't work).
Ended up forking the project myself, but it turns out the original project is broken anyway.

Composer not composing - saying file not found

I'm using the excellent phpwkhtmltopdf library and want to update to latest version and for this I need to use composer.
File structure:
vendor
--mikehaertl
--php-shellcommand
--php-tmpfile
autoload.php
Composer.json file:
{
"name": "mikehaertl/phpwkhtmltopdf",
"description": "A slim PHP wrapper around wkhtmltopdf with an easy to use and clean OOP interface",
"keywords": ["pdf", "wkhtmltopdf", "wkhtmltoimage" ],
"homepage": "http://mikehaertl.github.com/phpwkhtmltopdf/",
"type": "library",
"license": "MIT",
"authors": [
{
"name": "Michael Haertl",
"email": "haertl.mike#gmail.com"
}
],
"require": {
"php": ">=5.0.0",
"mikehaertl/php-tmpfile": "1.0.*",
"mikehaertl/php-shellcommand": "1.0.*"
},
"autoload": {
"psr-4": {
"mikehaertl\\wkhtmlto\\": "src/"
}
},
"extra": {
"branch-alias": {
"dev-master": "2.0.x-dev"
}
}
}
I'm trying to use the library like this:
require '/home/bookmark/vendor/autoload.php';
use mikehaertl\wkhtmlto\Pdf;
...
$pdf = new Pdf('http://anysite.com'); <-- error points to this line
The problem is I get the error:
Fatal error: Class 'mikehaertl\wkhtmlto\Pdf' not found in /home/bookmark/public_html/ajax/action.php on line 132
This is my first time using composer, any idea what I'm doing wrong?
If you are using some package, you must not copy their composer.json file - that won't work.
The best thing would be to run composer init once to create an initial composer.json file for your project, and composer require mikehaertl/phpwkhtmltopdf:~2.0 to add this package you want to work with.
After that, it should work.

GitHub repository autoloading with Composer issue

I got PHP Fatal error: Class 'sendwithus\sendwithus_php\lib\API' not found
composer.json:
{
"repositories": {
"sendwithus_php": {
"type": "package",
"package": {
"name": "sendwithus/sendwithus_php",
"version": "1.0.3",
"source": {
"url": "https://github.com/sendwithus/sendwithus_php",
"type": "git",
"reference": "0dfed56"
}
}
}
},
"require": {
"sendwithus/sendwithus_php": ">=1.0.3"
}, "autoload": {
"psr-0": {
"Foo\\": "src/",
"sendwithus\\": "vendor/sendwithus/sendwithus_php/lib"
}
}, "minimum-stability" : "dev"
}
test.php:
use sendwithus\sendwithus_php\lib\API;
require_once 'vendor/autoload.php';
$api = new API('KEY');
What am I doing wrong?
There is a bunch of stuff going wrong in your case. I'll try to correct it as well as I can.
First I took a look at the library you are requiring. It is public on Github, and it has a composer.json file that has errors.
{
"name": "sendwithus/api",
"version": "1.0.3",
"require": {},
"repositories": [
{
"type": "vcs",
"url": "https://github.com/sendwithus/sendwithus_php"
}
]
}
These infos are slightly wrong. Only the name is correctly formatted.
There shouldn't be a version. Versions are detected by tagging the code in git.
If nothing is required, that key can be omitted.
The current repository URL shouldn't be included in it's own repository.
Mentioning a license would be nice - currently everybody using this library should be scared about violating copyright.
The important, but missing info: How is autoloading configured?
Investigating the contents of that repository quickly reveals that it does not conform to PSR-0, so the only viable alternativ is classmap autoloading - which is sufficient enough because there are only two files in the lib folder.
A correct autoloading definition would be:
"autoload": {
"classmap": ["lib"]
}
Details on how to construct this are in http://getcomposer.org/doc/04-schema.md#classmap Effectively, the value for the classmap key is a list of directories relative to the repository root directory that should be indexed.
The test folder need not be mentioned here. Using PHPUnit, that folder would be scanned for any file containing test classes. The test bootstrap should include the vendor/autoload.php file generated by Composer.
I don't know if the OP is responsible for this repository or can change it. This info above should be implemented in the repository itself, but it is also helpful if it cannot, because it can also go into a "package" definition.
So now we are going to look at the mentioned composer.json of the OP:
{
"repositories": {
"sendwithus_php": {
"type": "package",
"package": {
"name": "sendwithus/sendwithus_php",
"version": "1.0.3",
"source": {
"url": "https://github.com/sendwithus/sendwithus_php",
"type": "git",
"reference": "0dfed56"
}
}
}
},
"require": {
"sendwithus/sendwithus_php": ">=1.0.3"
}, "autoload": {
"psr-0": {
"Foo\\": "src/",
"sendwithus\\": "vendor/sendwithus/sendwithus_php/lib"
}
},
"minimum-stability" : "dev"
}
The "repositories" key can contain objects that are of type "package" that contain all the necessary info of a project that fails to do so, or fails to do correctly. As I mentioned, the autoloading is broken in the original definition, so it must be fixed here:
"sendwithus_php": {
"type": "package",
"package": {
"name": "sendwithus/api",
"version": "1.0.3",
"source": {
"url": "https://github.com/sendwithus/sendwithus_php",
"type": "git",
"reference": "0dfed56"
},
"autoload": {
"classmap": ["lib"]
}
}
}
This would correctly reference that repository and enable autoloading. Note that the name has changed here to the original - it would probably trigger trouble if this library is known under two different names (one defined here, and the other in the original repository), but using the same namespace and class names.
Now that the repository info is fixed, all other things work as usual in composer.json.
"require": {
"sendwithus/api": "1.0.3"
},
"autoload": {
"psr-0": {
"Foo\\": "src/"
}
},
"minimum-stability" : "dev"
Note that the autoloading defined here is for THIS library or application only. Do not include the autoloading of the dependencies here!
And then we take care of your code:
use sendwithus\sendwithus_php\lib\API;
require_once 'vendor/autoload.php';
$api = new API('KEY');
The namespace is wrong. Don't use the name from Composer. Use the name from the code you are importing. This is correct:
require_once __DIR__ . "../vendor/autoload.php";
use sendwithus\API;
$api = new API("apikey");
Note that you cannot change the namespace of the library with a rename in Composer. Composer only downloads the PHP source files for you, it does not change the code inside the files.
My final composer.json file is this:
{
"repositories": {
"sendwithus_php": {
"type": "package",
"package": {
"name": "sendwithus/api",
"version": "1.0.3",
"source": {
"url": "https://github.com/sendwithus/sendwithus_php",
"type": "git",
"reference": "0dfed56"
},
"autoload": {
"classmap": ["lib"]
}
}
}
},
"require": {
"sendwithus/api": "1.0.3",
},
"autoload": {
"psr-0": {
"Foo\\": "src/"
}
},
"minimum-stability": "dev"
}
If you have a standard directory structure (as in vendor/sendwithus/sendwithus_php/lib) You will need to modify the path to be relative to the composer.json of that package:
"sendwithus\\": "vendor/sendwithus/sendwithus_php/lib"
Becomes:
"sendwithus\\": "lib/"
Take a look at vendor/composer/autoload_namespaces.php Which should list the path that is being used. Notice how composer will prepend the $vendorDir for you so your namespace should not need to reference it
An example from my project:
'Core\\' => array($vendorDir . '/alex-patterson-webdev/core/src'),

Categories