Composer - Setup autoload in new package - php

I'm trying to make a composer package, but I'm struggling to setup the autoload to work in the project where I'm developing it.
I have two projects:
Project Foo (where I'm developing the package).
Project Bar (where I've installed the package: composer require myhandle/mypackage).
In Project Foo I (obviously) have to be able to use the package as well. But setting up the autoload in my own package is not working.
However... When I commit the changes to Github, update the package at Packagist and run composer update in Project Bar, then it works(?!).
And wierdly enough... If I do composer update from Project Foo (the project where it isn't working). So updating the package to it's current version (?), makes it start working.
So it must somehow be related to how I've setup the autoload.
A note:
I started the package by making a new (empty) folder in the vendor directory, and then build the package there. I figured it was smart, since it then would mirror how it would look had I composer required the package.
I don't know if this is bad practice, since Composer no longer 'are in control' of all files in the vendor directory.
There are tons of guides on how to make a composer package out there, - but non of them explains about a good way to structure the files in the project where the package is being developed.
Here's what I do to 'get the error' (in Project Foo):
Create new class file, such as: myhandle/mypackage/src/Test.php
Then I instantiate it like this: $test = new MyNamespace\MyPackageName\Test();
And then I get the error:
Fatal error: Uncaught Error: Class 'MyNamespace\MyPackageName\Test' not found
And this is what works in Project Bar (the very same code).
I can't find a guide on how to correctly setup autoload in the package I'm developing. I'm using this autoload file, that I found in another composer project. I've put it in the root of my project. It looks like this:
<?php
namespace MyNamespace\MyPackageName;
spl_autoload_register(function($cls) {
$cls = ltrim($cls, '\\');
if (strpos($cls, __NAMESPACE__) !== 0) {
return;
}
$classWithoutBaseNamespace = str_replace(__NAMESPACE__, '', $cls);
// Load files from 'src' directory based on their class name without
// the StoutLogic\AcfBuilder namespace.
$path = dirname(__FILE__).
DIRECTORY_SEPARATOR.
'src'.
str_replace('\\', DIRECTORY_SEPARATOR, $classWithoutBaseNamespace).
'.php';
require_once($path);
});
I can't find it in the Composer Documentation, how to set it up in a new project/package. However I can find a bazillions guides on how to use autoload.

As yivi and Daniel Protopopov pointed out:
Check the documentation at getcomposer.org regarding autoloading
Delete your custom autoloader definition, register your namespace in composer.json (hoping you follow PSR-4 already), run composer dump-autoload.
Last but not least, when- and wherever you need to use it, just include the
require __DIR__ . '/vendor/autoload.php';

Related

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.

Adding composer into Codeigniter

I am using Codeigniter since a year and I also started learning Laravel recently and I noticed that having a composer in your framework really helps you in a many ways.
I notice that the Codeigniter 3 has this option in config.php file to add a composer in it.
$config['composer_autoload'] = TRUE;
so I am thinking to add a composer in my CI.
Is it best practice to add a Composer in CI?
What should be the directory structure for that and is it work smoothly with the CI?
This is how I implemented composer in CodeIgniter 3.It is very easy. You have to install composer on your machine and I think you have it because you use laravel.
First copy and paste composer.json file in the project folder to application folder
Secound in the config.php file $config['composer_autoload'] = TRUE;
Now you have composer in your project. I will saw you an example like how to install mpdf using composer
Open cmd and direct to application folder
Inside application directory Type composer require mpdf/mpdf
Now a vendor folder will be created inside application folder and inside vendor
folder you can see all your packages downloaded by composer.
Now since you autoloaded composer now you can just use the code given by mpdf official manual like
function m_pdf()
{
$mpdf = new mPDF();
// Write some HTML code:
$mpdf->WriteHTML('Hello World');
// Output a PDF file directly to the browser
$mpdf->Output();
}
You can install any packages in https://packagist.org/ like mpdf very simply like this. Remember you don't need to type require_once APPPATH.'/vendor/mpdf/mpdf/mpdf.php'; since you already autoloader composer. If not prefer to autoload composer you must type require_once APPPATH.'/vendor/mpdf/mpdf/mpdf.php' at the beginning of each controllers where you use the mpdf vendor libraries.
in my experience, the best way is installing composer and dependencies independent of CodeIgniter, like 'composer require ', and then give access to the packages in your base controller.
add a file MY_Controller.php to application/core folder and make it extend CI_Controller. then add require_once(APPPATH . 'vendor/autoload.php') at the top. make all your controllers extend this base class, and you have access to all your packages. the same goes if you wanna access them in your models. make the base class MY_Model.php

How do I include a composer package into plain php?

Good afternoon, I will start off by saying that I've never included a composer project in my projects unless it was a composer package for the Laravel framework. Where you "require" it and add it to the providers array and aliases if needed.
Now, the problem. I have a composer package I'm trying to play around with https://github.com/WHAnonymous/Chat-API the problem is i dont know how to include it into myu project since its not really made "for" laravel. So I'm trying to use plain php without a framework but I have no idea how to "load" the package in, tried googling and only found information regarding building a package.
To clarify: I can install the package fine, its the php part of "loading" the package in my index.php file that im struggling with, pretend the index.php file is empty.
Can someone please help me?
After installing the package with composer, the composer has generated an autoloader that you can include with:
require_once 'vendor/autoload.php';
Then you can use the classes of the package without further includes. In your example this might be:
// Create an instance of WhatsProt.
$w = new WhatsProt($username, $nickname, $debug);
(taken from https://github.com/WHAnonymous/Chat-API/blob/master/examples/exampleRegister.php)
Note that this line from the example is not necessary, when you use the composer autoloader:
require_once('../src/whatsprot.class.php');
Assuming you have composer installed and have gone through the basics in the link posted by Paul.
You would run the following
~/composer install (same directory your composer.json file resides in).
Contents of composer.json file would be:
{
"require" : {
"whatsapp/chat-api" : "2.5.4"
}
}

Reference .phar classes installed globally with composer

I've created a small command line tool in PHP and I've also packed that as a PHAR archive.
Next thing I did was publish my archive to packagist.org aka composer.
I can now install my PHAR package through composer like so:
composer global require acme/mypackage
This installs my package fine. And I'm able to run it through command as well.
So far so good, but here comes the problem I´m currently facing.
I have another project should use acme/mypackage. I want that project to reference a class that is packed into that PHAR. Something like this:
<?php
class SomeClass extends AcmeClass {
}
The problem is that the PHP code doesn't recognize the AcmeClass class. Makes sense, because it´s obviously "globally" installed somewhere on the system.
How do other libraries solve this issue? If I'm not mistaken then PHPUnit does something similar right?
How can I solve this issue?
You'll need to add a composer.json file to the root of your project:
The first (and often only) thing you specify in composer.json is the require key. You're simply telling Composer which packages your project depends on.
{
"require": {
"monolog/monolog": "1.0.*"
}
}
Next, you'll need to autoload your dependencies.
For libraries that specify autoload information, Composer generates a vendor/autoload.php file. You can simply include this file and you will get autoloading for free.
require 'vendor/autoload.php';
https://getcomposer.org/doc/01-basic-usage.md

PHP Zend library results in Fatal Error: class 'Zend\[whatever]' not found

I'm hoping someone can spot what I've forgotten to do. Here are my steps:
Downloaded and unpacked the ZendFramework-2.3.5 into /usr/share.
Updated include_path in my php.ini file to include '/usr/share/ZendFramework-2.3.5/library' per the INSTALL.md, and restarted Apache to confirm the path is set (now ".:/usr/share/php:/usr/share/ZendFramework-2.3.5/library").
Created a test script in my web document root (using the class 'CamelCaseToUnderscore' as an example):
use Zend\Filter\Word\CamelCaseToUnderscore;
$filter = new CamelCaseToUnderscore();
echo $filter->filter('BigsAndLittles');
...and I get the fatal error "class 'zend\filter\word\camelcasetoseparator' not found".
In order to do use Zend classes like this, do I need to do some additional configuration or create an autoloader or something to find them? Seems like this should have worked. If I include the CamelCaseToUnderscore.php file in a require_once statement, then I get a fatal error that it's parent class doesn't exist (CamelCaseToSeparator.php). What am I missing?
You can use require 'Zend/Mvc/Application.php' to test if your include path is correct, but you will need an autoloader:
http://framework.zend.com/manual/current/en/modules/zend.loader.standard-autoloader.html.
You can find an example here (lines 18-20):
https://github.com/zendframework/zf2/blob/master/demos/Zend/Feeds/consume-feed.php
I strongly suggest using composer as it will save you a lot of time troubleshooting your include paths, but it also allows you manage version better. It makes it easier for other developers and to deploy your code.
Starting with composer is very easy, just install it and create composer.json:
https://getcomposer.org/doc/01-basic-usage.md#composer-json-project-setup
Run:
composer require zendframework/zendframework
Composer will download all libraries to vendor folder and will generate an autoloader, all you have to do is to include
require 'vendor/autoload.php';
https://getcomposer.org/doc/01-basic-usage.md#autoloading
Most popular PHP frameworks use composer for managing dependencies:
https://github.com/zendframework/zf2/blob/master/composer.json
https://github.com/symfony/symfony/blob/2.7/composer.json

Categories