(29 intermediate revisions by 2 users not shown) | |||
Line 42: | Line 42: | ||
* "'''require'''" becomes "Requires", using the virtual php-composer(foo) | * "'''require'''" becomes "Requires", using the virtual php-composer(foo) | ||
* "'''require-dev'''" usually becomes "BuildRequires" | * "'''require-dev'''" usually becomes "BuildRequires" | ||
* "'''suggest'''" are optional dependencies, which can becomes (packager choice) "Requires" | * "'''suggest'''" are optional dependencies, which can becomes (packager choice) "Requires", "Recommends" or "Suggests" | ||
* "'''conflict'''" becomes "Conflicts" | * "'''conflict'''" becomes "Conflicts" (be careful, usually not needed) | ||
* "'''replace'''" becomes "Provides" (and "Obsoletes" if needed) | * "'''replace'''" becomes "Provides" (and "Obsoletes" if needed) | ||
Line 70: | Line 70: | ||
} | } | ||
</pre> | </pre> | ||
the | The simplest solution is to generate an simple classmapp autoloader, using the fedora/autoloder, e.g. | ||
<pre> | |||
BuildRequires: php-fedora-autoloader-devel | |||
Requires: php-composer(fedora/autoloader) | |||
%build | |||
%{_bindir}/phpab --template fedora --output src/autoload.php src | |||
</pre> | |||
Another deprecated solution is to generate an simple classmap autoloader, only using the '''phpab''' command, e.g. | |||
<pre> | <pre> | ||
BuildRequires: %{_bindir}/phpab | BuildRequires: %{_bindir}/phpab | ||
Line 78: | Line 87: | ||
</pre> | </pre> | ||
''' | '''PSR-0/PSR-4''' when "composer.json" describe a library as compliant: | ||
<pre> | <pre> | ||
"require": { | "require": { | ||
"php": ">=5.3.2", | "php": ">=5.3.2", | ||
"symfony/console": "~2.5", | "symfony/console": "~2.5 || ~3.0", | ||
"foo/baz": "~1.0" | "foo/baz": "~1.0" | ||
}, | }, | ||
Line 90: | Line 99: | ||
}, | }, | ||
</pre> | </pre> | ||
Using the new '''fedora/autoloader''': | |||
<pre> | |||
BuildRequires: php-composer(fedora/autoloader) | |||
Requires: php-composer(fedora/autoloader) | |||
cat <<'AUTOLOAD' | tee src/Foo/Bar/autoload.php | |||
<?php | |||
require_once '%{_datadir}/php/Fedora/Autoloader/autoload.php'; | |||
\Fedora\Autoloader\Autoload::addPsr4('Foo\\Bar\\', __DIR__); | |||
\Fedora\Autoloader\Dependencies::required(array( | |||
'%{_datadir}/php/Foo/Baz/autoload.php', | |||
array( | |||
'%{_datadir}/php/Symfony3/Component/Console/autoload.php', // SF3 preferred | |||
'%{_datadir}/php/Symfony/Component/Console/autoload.php', // SF2 as fallback | |||
))); | |||
\Fedora\Autoloader\Dependencies::optional(array( | |||
// no optional dependencies | |||
)); | |||
AUTOLOAD | |||
</pre> | |||
'''Notice''': this solution reduce the dependency tree, avoiding pulling some big framework. It will also avoid some conflicts when multiple version of the Framework exist. | |||
'''Symfony Framework''': alternative solution when your package already pull some symfony components and is PSR-0/PSR-4 compliant, e.g. | |||
In your spec (autoload.php can also be a separate source file): | In your spec (autoload.php can also be a separate source file): | ||
<pre> | <pre> | ||
Line 117: | Line 156: | ||
'''Notice''': in this implementation proposal, ''$fedoraClassLoader'' can be shared between libraries when various autoloader are stacked. | '''Notice''': in this implementation proposal, ''$fedoraClassLoader'' can be shared between libraries when various autoloader are stacked. | ||
'''Zend Framework''': | '''Zend Framework''': alternative solution when your package already pull some ZF components. | ||
In your spec (autoload.php can also be a separate source file): | In your spec (autoload.php can also be a separate source file): | ||
Line 162: | Line 201: | ||
! Autoloader Type | ! Autoloader Type | ||
! Autoloader Since Version | ! Autoloader Since Version | ||
|- | |||
|php-Analog | |||
|phpab | |||
|1.0.7 | |||
|- | |- | ||
|php-Assetic | |php-Assetic | ||
| | |Symfony ClassLoader | ||
| | |1.2.1-4 | ||
|- | |- | ||
|php-aws-sdk | |php-aws-sdk | ||
|Symfony ClassLoader | |Symfony ClassLoader | ||
|2. | |2.6.15 | ||
|- | |- | ||
|php-deepend-Mockery | |php-deepend-Mockery | ||
| | |Symfony ClassLoader | ||
| | |0.9.3 | ||
|- | |- | ||
|php-digitalsandwich-Phake | |php-digitalsandwich-Phake | ||
Line 197: | Line 236: | ||
|php-doctrine-common | |php-doctrine-common | ||
|Symfony ClassLoader | |Symfony ClassLoader | ||
|2.5.0 | |el6: 2.4.3 / !el6: 2.5.0 | ||
|- | |- | ||
|php-doctrine-datafixtures | |php-doctrine-datafixtures | ||
Line 204: | Line 243: | ||
|- | |- | ||
|php-doctrine-dbal | |php-doctrine-dbal | ||
| | |Symfony ClassLoader | ||
| | |el6: 2.4.5 / !el6: 2.5.4 | ||
|- | |- | ||
|php-doctrine-Doctrine | |php-doctrine-Doctrine | ||
Line 220: | Line 259: | ||
|- | |- | ||
|php-doctrine-orm | |php-doctrine-orm | ||
| | |Symfony ClassLoader | ||
| | |2.4.8 | ||
|- | |- | ||
|php-dropbox-php-Dropbox | |php-dropbox-php-Dropbox | ||
Line 240: | Line 279: | ||
|- | |- | ||
|php-Faker | |php-Faker | ||
| | |Symfony ClassLoader | ||
| | |1.5.0 | ||
|- | |- | ||
|php-gitter | |php-gitter | ||
Line 256: | Line 295: | ||
|- | |- | ||
|php-goutte | |php-goutte | ||
| | |Symfony ClassLoader | ||
| | |1.0.7-3 | ||
|- | |- | ||
|php-guzzle-Guzzle | |php-guzzle-Guzzle | ||
Line 274: | Line 313: | ||
|Symfony ClassLoader | |Symfony ClassLoader | ||
|3.0.0-3 | |3.0.0-3 | ||
|- | |||
|php-ircmaxell-random-lib | |||
|class map | |||
|1.1.0-3 | |||
|- | |||
|php-ircmaxell-security-lib | |||
|class map | |||
|1.1.0-4 | |||
|- | |- | ||
|php-JMSParser | |php-JMSParser | ||
Line 280: | Line 327: | ||
|- | |- | ||
|php-jsonlint | |php-jsonlint | ||
| | |Symfony ClassLoader | ||
| | |1.3.1-3 | ||
|- | |- | ||
|php-JsonSchema | |php-JsonSchema | ||
Line 304: | Line 351: | ||
|- | |- | ||
|php-ocramius-code-generator-utils | |php-ocramius-code-generator-utils | ||
| | |Symfony ClassLoader | ||
| | |0.3.2-4 | ||
|- | |- | ||
|php-ocramius-generated-hydrator | |php-ocramius-generated-hydrator | ||
| | |Symfony ClassLoader | ||
| | |1.2.0 | ||
|- | |- | ||
|php-opencloud | |php-opencloud | ||
| | |Symfony ClassLoader | ||
| | |1.12.2 | ||
|- | |- | ||
|php-pclzip | |php-pclzip | ||
Line 326: | Line 373: | ||
| | | | ||
| | | | ||
|- | |||
|php-PHP-Css-Parser | |||
|phpab | |||
|7.0.2 | |||
|- | |- | ||
|php-PhpCollection | |php-PhpCollection | ||
Line 348: | Line 399: | ||
|- | |- | ||
|php-PsrLog | |php-PsrLog | ||
| | |Symfony ClassLoader | ||
| | |1.0.0-8 | ||
|- | |- | ||
|php-Raven | |php-Raven | ||
Line 394: | Line 445: | ||
| | | | ||
| | | | ||
|- | |||
|php-seld-cli-prompt | |||
|Symfony ClassLoader | |||
|1.0.0-3 | |||
|- | |||
|php-seld-phar-utils | |||
|Symfony ClassLoader | |||
|1.0.1 | |||
|- | |||
|php-solarium | |||
|Symfony ClassLoader | |||
|3.5.0 | |||
|- | |- | ||
|php-symfony | |php-symfony | ||
|Symfony ClassLoader | |Symfony ClassLoader | ||
|2.3.31 / 2.7.1 | |el6: 2.3.31 / !el6: 2.7.1 | ||
|- | |- | ||
|php-SymfonyCmfRouting | |php-SymfonyCmfRouting | ||
| | |Symfony ClassLoader | ||
| | |1.3.0-4 | ||
|- | |- | ||
|php-twig | |php-twig | ||
Line 408: | Line 471: | ||
|- | |- | ||
|php-twig-extensions | |php-twig-extensions | ||
| | |Twig_Extensions_Autoloader | ||
| | |1.3.0 | ||
|- | |- | ||
|php-when | |php-when | ||
Line 420: | Line 483: | ||
|- | |- | ||
|php-ZendFramework2 | |php-ZendFramework2 | ||
| | |Zend | ||
| | |el6: 2.2.10 / !el6: 2.4.7 | ||
|} | |} | ||
[[Category:PHP]] | [[Category:PHP]] |
Latest revision as of 09:26, 5 December 2019
PHP Packaging Tips
Dependencies
PEAR/PECL
package.xml provided in pear/pecl channel archive describe the dependencies of the package, e.g.
<dependencies> <required> <php> <min>5.3.0</min> </php> <package> <name>Foo</name> <channel>pear.php.net</channel> <min>2.0.0</min> </package> </required> <optional> <extension> <name>curl</name> </extension> </optional> </dependencies>
In your spec
# From package.xml - required Requires: php(language) >= 5.3.0 Requires: php-pear(Foo) >= 2.0.0 # From package.xml - optional Requires: php-curl
composer
composer.json provided in lot of libraries/applications describes the dependencies.
- "require" becomes "Requires", using the virtual php-composer(foo)
- "require-dev" usually becomes "BuildRequires"
- "suggest" are optional dependencies, which can becomes (packager choice) "Requires", "Recommends" or "Suggests"
- "conflict" becomes "Conflicts" (be careful, usually not needed)
- "replace" becomes "Provides" (and "Obsoletes" if needed)
Autoloader
Explanation
Composer: most library and lot of applications are now "composer" aware. Which means composer is used to install dependencies and create a suitable autoloader. Composer is mostly a "Bundled every library in every project", not something we want in Fedora.
Consumer Autoloader: in some case, we can add an autoloader for an application and all its dependencies. It seems this is not the best solution, if the dependency tree change, the autoloader need to be fixed.
Provider Autoloader: if each library provides an autoloader for its classes and its dependencies, a consumer just have to include this autoloader. This seems the best solution, so recommended here.
Providing an autoloader is not mandatory (so not in the Guidelines), but seems a good practice.
Implementation
There are various way to create an autoloader
upstream: when upstream provides an autoloader, no need to use another one ;)
classmap: when "composer.json" describe a library to autoload a classmap, e.g.
"autoload": { "classmap": ["src/"] }
The simplest solution is to generate an simple classmapp autoloader, using the fedora/autoloder, e.g.
BuildRequires: php-fedora-autoloader-devel Requires: php-composer(fedora/autoloader) %build %{_bindir}/phpab --template fedora --output src/autoload.php src
Another deprecated solution is to generate an simple classmap autoloader, only using the phpab command, e.g.
BuildRequires: %{_bindir}/phpab %build %{_bindir}/phpab --output src/autoload.php src
PSR-0/PSR-4 when "composer.json" describe a library as compliant:
"require": { "php": ">=5.3.2", "symfony/console": "~2.5 || ~3.0", "foo/baz": "~1.0" }, "autoload": { "psr-0": { "Foo\\Bar\\": "src/" } },
Using the new fedora/autoloader:
BuildRequires: php-composer(fedora/autoloader) Requires: php-composer(fedora/autoloader) cat <<'AUTOLOAD' | tee src/Foo/Bar/autoload.php <?php require_once '%{_datadir}/php/Fedora/Autoloader/autoload.php'; \Fedora\Autoloader\Autoload::addPsr4('Foo\\Bar\\', __DIR__); \Fedora\Autoloader\Dependencies::required(array( '%{_datadir}/php/Foo/Baz/autoload.php', array( '%{_datadir}/php/Symfony3/Component/Console/autoload.php', // SF3 preferred '%{_datadir}/php/Symfony/Component/Console/autoload.php', // SF2 as fallback ))); \Fedora\Autoloader\Dependencies::optional(array( // no optional dependencies )); AUTOLOAD
Notice: this solution reduce the dependency tree, avoiding pulling some big framework. It will also avoid some conflicts when multiple version of the Framework exist.
Symfony Framework: alternative solution when your package already pull some symfony components and is PSR-0/PSR-4 compliant, e.g.
In your spec (autoload.php can also be a separate source file):
BuildRequires: php-composer(symfony/class-loader) Requires: php-composer(symfony/class-loader) cat <<'AUTOLOAD' | tee src/autoload.php <?php if (!isset($fedoraClassLoader) || !($fedoraClassLoader instanceof \Symfony\Component\ClassLoader\ClassLoader)) { if (!class_exists('Symfony\\Component\\ClassLoader\\ClassLoader', false)) { require_once '%{_datadir}/php/Symfony/Component/ClassLoader/ClassLoader.php'; } $fedoraClassLoader = new \Symfony\Component\ClassLoader\ClassLoader(); $fedoraClassLoader->register(); } // This library $fedoraClassLoader->addPrefix('Foo\\Bar\\', dirname(dirname(__DIR__))); // Another library (dependency) require_once '%{_datadir}/php/Foo/Baz/autoload.php'; AUTOLOAD
Notice: in this implementation proposal, $fedoraClassLoader can be shared between libraries when various autoloader are stacked.
Zend Framework: alternative solution when your package already pull some ZF components.
In your spec (autoload.php can also be a separate source file):
BuildRequires: php-composer(zendframework/zend-loader) Requires: php-composer(zendframework/zend-loader) cat <<'AUTOLOAD' | tee src/autoload.php <?php require_once '%{_datadir}/php/Zend/Loader/AutoloaderFactory.php'; Zend\Loader\AutoloaderFactory::factory(array( 'Zend\Loader\StandardAutoloader' => array( 'fallback_autoloader' => true, // for other dep, if needed 'autoregister_zf' => true, // for ZF, if needed 'namespaces' => array( 'Foo\\Bar' => __DIR__ // Your namespace )))); AUTOLOAD
Using AutoloaderFactory ensure a single instance of StandardAutoloader is used.
More autoloader tips
Test your autoloader: usually by using it to run the test suite, and better to run the installed copy, e.g.
%check phpunit --bootstrap=%{buildroot}/%{_datadir}/php/Foo/Bar/autoload.php
Use full path to dependencies autoloader, to ensure you use the expected one (don't rely on include_path to avoid /usr/share/pear which can provide an old version, or SCL which doesn't includes /usr/share/php, or any user altered env.)
Use relative path for the library itself, so the autoloader can be included from /usr/share/php or %{buildroot}
Package versions that introduced autoloaders
Package | Autoloader Type | Autoloader Since Version |
---|---|---|
php-Analog | phpab | 1.0.7 |
php-Assetic | Symfony ClassLoader | 1.2.1-4 |
php-aws-sdk | Symfony ClassLoader | 2.6.15 |
php-deepend-Mockery | Symfony ClassLoader | 0.9.3 |
php-digitalsandwich-Phake | ||
php-doctrine-annotations | Symfony ClassLoader | 1.2.6 |
php-doctrine-cache | Symfony ClassLoader | 1.4.1 |
php-doctrine-collections | Symfony ClassLoader | 1.3.0 |
php-doctrine-common | Symfony ClassLoader | el6: 2.4.3 / !el6: 2.5.0 |
php-doctrine-datafixtures | Symfony ClassLoader | 1.0.2 |
php-doctrine-dbal | Symfony ClassLoader | el6: 2.4.5 / !el6: 2.5.4 |
php-doctrine-Doctrine | ||
php-doctrine-inflector | Symfony ClassLoader | 1.0.1-4 |
php-doctrine-lexer | Symfony ClassLoader | 1.0.1-4 |
php-doctrine-orm | Symfony ClassLoader | 2.4.8 |
php-dropbox-php-Dropbox | ||
php-drush-drush | ||
php-EasyRdf | Symfony ClassLoader | 0.9.0 |
php-egulias-email-validator | Symfony ClassLoader | 1.2.9 |
php-Faker | Symfony ClassLoader | 1.5.0 |
php-gitter | Symfony ClassLoader | 0.3.0-5 |
php-gliph | Symfony ClassLoader | 0.1.8-4 |
php-google-apiclient | Upstream custom | 1.1.4 |
php-goutte | Symfony ClassLoader | 1.0.7-3 |
php-guzzle-Guzzle | Symfony ClassLoader | 3.9.3 |
php-guzzlehttp-guzzle | Symfony ClassLoader | 5.3.0 |
php-guzzlehttp-ringphp | Symfony ClassLoader | 1.1.0-3 |
php-guzzlehttp-streams | Symfony ClassLoader | 3.0.0-3 |
php-ircmaxell-random-lib | class map | 1.1.0-3 |
php-ircmaxell-security-lib | class map | 1.1.0-4 |
php-JMSParser | Symfony ClassLoader | 1.0.0-7 |
php-jsonlint | Symfony ClassLoader | 1.3.1-3 |
php-JsonSchema | ||
php-lessphp | ||
php-Metadata | Symfony ClassLoader | 1.5.1-3 |
php-mikey179-vfsstream | phpab | 1.6.0 |
php-Monolog | Symfony ClassLoader | 1.15.0 |
php-ocramius-code-generator-utils | Symfony ClassLoader | 0.3.2-4 |
php-ocramius-generated-hydrator | Symfony ClassLoader | 1.2.0 |
php-opencloud | Symfony ClassLoader | 1.12.2 |
php-pclzip | ||
php-pear-PhpDocumentor | ||
php-phpass | ||
php-PHP-Css-Parser | phpab | 7.0.2 |
php-PhpCollection | Symfony ClassLoader | 0.4.0-4 |
php-PhpOption | Symfony ClassLoader | 1.4.0-4 |
php-PHPParser | ||
php-pirum-Pirum | ||
php-psr-http-message | phpab | 1.0.0 |
php-PsrLog | Symfony ClassLoader | 1.0.0-8 |
php-Raven | Raven_Autoloader | 0.12.0 |
php-react-promise | Symfony ClassLoader | 2.2.0-4 |
php-sabredav-Sabre | ||
php-sabredav-Sabre_CalDAV | ||
php-sabredav-Sabre_CardDAV | ||
php-sabredav-Sabre_DAV | ||
php-sabredav-Sabre_DAVACL | ||
php-sabredav-Sabre_HTTP | ||
php-sabredav-Sabre_VObject | ||
php-scssphp | Symfony ClassLoader | 0.1.6 |
php-swift-Swift | ||
php-seld-cli-prompt | Symfony ClassLoader | 1.0.0-3 |
php-seld-phar-utils | Symfony ClassLoader | 1.0.1 |
php-solarium | Symfony ClassLoader | 3.5.0 |
php-symfony | Symfony ClassLoader | el6: 2.3.31 / !el6: 2.7.1 |
php-SymfonyCmfRouting | Symfony ClassLoader | 1.3.0-4 |
php-twig | Twig_Autoloader | 1.18.2 |
php-twig-extensions | Twig_Extensions_Autoloader | 1.3.0 |
php-when | ||
php-xmlseclibs | ||
php-ZendFramework2 | Zend | el6: 2.2.10 / !el6: 2.4.7 |