48
PHP Usergroup Munich 2015-01-28 HELPDESK

Composer Helpdesk

Embed Size (px)

Citation preview

Page 1: Composer Helpdesk

PHP Usergroup Munich2015-01-28

HELPDESK

Page 2: Composer Helpdesk

About me

● Sven Rautenberg● Developing with PHP for >15 years now● Currently working for Kabel Deutschland

– Doing API stuff for ordering GUI interfaces

– aka the PHP middleware in front of the Java middleware

● I do have a past at SELFHTML (selfhtml.org)● Some activity at Stackoverflow for PHP, Log4php and Composer● Twitter: @SvenRtbg

Page 3: Composer Helpdesk

Questions

● Please ask at once– anything directly related to the current slide

– me not cleanly explaining stuff, talking too fast or incomprehensible

● Try to wait until the end, Q&A session– anything broader, which may be answered by an upcoming slide

– your own examples of Composer usage, failure and fixes

Page 4: Composer Helpdesk

How to generally use it

● On 1 slide, because you already know it (or should):– getcomposer.org is the main page for software and documentation

– downloading Composer from there is a one line CLI command

curl -sS https://getcomposer.org/installer | php– mind the security implications of this command (discussed later)

– for convenience: symlink/rename/move the downloaded phar file to composer and make it available in your $PATH

– This should work anywhere now:

composer –-help

Page 5: Composer Helpdesk

Now let Composer do the work for you

● You have an existing project, or want to start a new● Go to the root folder (top level GIT folder etc.)● Use the command line

composer init– This asks a lot of questions, with sensible default answers.

– creates the initial composer.json in less than a minute.

Page 6: Composer Helpdesk

vagrant@vbox /home/vagrant/myapplication $ composer init

Welcome to the Composer config generator

This command will guide you through creating your composer.json config.

Package name (<vendor>/<name>) [root/composer-demo]: fancy-devshop/myapplicationDescription []: Does useful stuff for everybody.Author [Jane Doe <[email protected]>]:Minimum Stability []:License []: proprietary

Page 7: Composer Helpdesk

Define your dependencies.

Would you like to define your dependencies (require) interactively [yes]? noWould you like to define your dev dependencies (require-dev) interactively [yes]? no

{ "name": "fancy-devshop/myapplication", "description": "Does useful stuff for everybody.", "license": "proprietary", "authors": [ { "name": "Jane Doe", "email": "[email protected]" } ], "require": {}}

Do you confirm generation [yes]?vagrant@vbox /home/vagrant/myapplication $

Page 8: Composer Helpdesk

Epic win!

● You just enabled your project to make use of Composer– it has a name attached to be identified.

– automatic detection of tagged versions and branches in it's repository

– started the list of contributors with the configured GIT default info● probably works with the other supported VCS as well

– the license is optional, “proprietary” is for non-open source● we are not going into details for this here

● Everything you did until now allows others to use your project, including yourself. We'll see some use cases later.

Page 9: Composer Helpdesk

Using others' code for your project

● The obvious usage: Include useful libraries● Main page to search: packagist.org● Hint:

– command line is easier than fiddling with the composer.json

composer require zendframework/zend-cache:~2.2

composer require --dev symfony/console:~2.3– and barely more typing

– will install the library if a version matches everything else, or roll back

– we get to the version details later on

Page 10: Composer Helpdesk

How to install a foreign library

1. Find a suitable library– It should do what you want (useful, secure, nice defaults etc.)

– It may match your style of programming

– It should have an amount of documentation that you are happy with

– It may have a reasonable number of installs according to Packagist

– It should (read as: MUST) have tagged releases as version numbers.

– The stability of the tagged releases don't matter as long as you can live with it.

– Reminder: Versions do come later in this talk.

Page 11: Composer Helpdesk

How to install a foreign library

2. Run Composer to fetch the code.composer require vendor/library:~1.0

3. Include the Composer autoloader in your bootstrappingrequire “vendor/autoload.php”;

4. Use the library classes, don't care about how to load them.

5. Profit!

Page 12: Composer Helpdesk

Using Composer for your own project

● Using the autoloading of Composer for your own project!● Multiple choices to make it work:

– PSR-4

– PSR-0

– classmap

– files

● Every existing code should be loadable via Composer somehow

Page 13: Composer Helpdesk

PSR-4

● Works for classes in namespaces only!● Allows for shallow directory structures● This autoload definition in composer.json

“Namespace\\” : “src/”

will autoload this class namenew \Namespace\Adapter\Foobar()

in this locationsrc/Adapter/Foobar.php

Page 14: Composer Helpdesk

PSR-4

● Works for classes in namespaces only!● Allows for shallow directory structures● This autoload definition in composer.json

“Namespace\\” : “src/”

will autoload this class namenew \Namespace\Adapter\Foobar()

in this locationsrc/Adapter/Foobar.php

Escapin

g a ba

cksla

sh

Page 15: Composer Helpdesk

PSR-4

● Works for classes in namespaces only!● Allows for shallow directory structures● This autoload definition in composer.json

“Namespace\\” : “src/”

will autoload this class namenew \Namespace\Adapter\Foobar()

in this locationsrc/Adapter/Foobar.php

No namespace in path

Page 16: Composer Helpdesk

PSR-0

● Works for classes in namespaces and Under_Scored_Classes!● This autoload definition in composer.json

“Namespace\\” : “src/”

will autoload this class namenew \Namespace\Adapter\Foobar()

in this locationsrc/Namespace/Adapter/Foobar.php

Page 17: Composer Helpdesk

PSR-0

● This autoload definition in composer.json“Under_Scores_” : “src/”

will autoload this class namenew Under_Scores_Adapter_Foobar()

in this locationsrc/Under/Scores/Adapter/Foobar.php

Page 18: Composer Helpdesk

PSR-0 What to avoid!

● This autoload definition in composer.json“” : “src/”

will autoload this class namenew Under_Scores_Adapter_Foobar()

in this locationsrc/Under/Scores/Adapter/Foobar.php

● Any will try to locate all other classes under src as well.● Failing to find the file here, will search in the next possible

location, but with useless file system lookups – is slow!

Page 19: Composer Helpdesk

PSR-0 What to avoid!

● A real example from this morning:– We are using a modified Zend Framework 1 with this autoloading:

“Zend” : “src”– and the stock Zend Framework 2 components

● Loading this class from ZF2new \Zend\EventManager\SharedEventManager()

will incorrectly detect this file as existing from ZF1src/Zend/Eventmanager/SharedEventManager.php

– which contains

class Zend_EventManager_SharedEventManager …

Page 20: Composer Helpdesk

PSR-4 & PSR-0 summary

● Prefer PSR-4 if possible– When you are using namespaces, use PSR-4!

● Aim for the longest possible or reasonable prefix!– Have an underscore or backslash at the end of the prefix!

– You can define multiple entries for different prefixes in your code base

“Models\\”: “lib/models/”

“Database_”: “lib/databases/”– If the same prefix is also used in a different code base, make it longer.

● PSR-0 can be converted to PSR-4 for namespaced classes“Namespace\\” : “src/” <=> “Namespace\\”: “src/Namespace/”

Page 21: Composer Helpdesk

Classmap

● If your code doesn't fit into PSR-4 or PSR-0 scheme.● Composer will scan all directories for PHP files containing

classes/interfaces/traits and will add them to a lookup array (aka classmap).

● Newly created files won't be added automatically! Annoying.composer dump-autoload

● Good for old code bases that you don't actively work on, but can't convert to PSR-* either.

Page 22: Composer Helpdesk

Classmap

● This definition“classmap”: [“src1/path”, “src2/path”]

will search for auto-loadable stuff in both directories.● Try to scan as few directories as possible - it will slow down any

Composer command that creates a new autoloader.● Don't impose it on everyone for PSR-0 or PSR-4 code because

“Classmaps are faster” - let them decide themselves withcomposer dump-autoload –optimize

● Performance discussion on Stackoverflow (link)

Page 23: Composer Helpdesk

Files

● The final method if all else fails.● Composer will always include the files you declare here, the

code is always available even if not needed.– Try to avoid doing slow things in these files.

● Use this for your functions that are not inside classes– Autoloading for functions doesn't exist yet.

– Maybe moving the functions to a class and call them statically instead.

● You may also add your own autoloading function here in case you cannot make classmap work for you.

Page 24: Composer Helpdesk

... "require": { "zendframework/zend-cache": "~2.2" }, "require-dev": { "symfony/console": "~2.3" }, "autoload": { "psr-4": { "Fancy\\": "src/fancystuff/" "Devshop\\: "library/Devshop/" }, "psr-0": { "Devshop_": "library/legacy/" }, "classmap": [ "library/non-fancy-stuff/" ] }}

Page 25: Composer Helpdesk

Epic win!

● Your own code is now autoloaded via Composer alongside all external libraries.

● All classes you might use anywhere in the code are available without first loading their code!

● You are only one step away from creating your own library that you can use in multiple of your own projects!

Page 26: Composer Helpdesk

Versions and Composer

● Composer does not impose any specific version scheme besides the fact that it has to be numeric.– No code names as version identifiers.

– One single integer number should work, but is uncommon.

● However Composer suggest to use semantic versioning and has convenient operators for this– Tilde operator: ~2.3

– Caret operator: ^4.4.2

Page 27: Composer Helpdesk

Semantic versioning: X.Y.Z

● Independent integers x,y,z, no float, more than one digit possible– Example 1.9.0 → 1.10.0 → 1.11.0

● Bugfixes: increase Z● Compatible new feature: increase Y● Incompatible new releases: increase X● Suffix like “alpha”, “beta”, “RC” allowed to denote lesser stability

– Denotes a version before the original, i.e. 1.0.0-alpha < 1.0.0

● More details: semver.org

Page 28: Composer Helpdesk

Tagging your library

● Try to stick to semantic versioning as closely as possible– It will make your life so much easier!

● 1.0 and 1.0.0 is semantically the same, but a different VCS tag!– Accidentially re-tagging 1.0 as 1.0.0 cannot be detected by your VCS

– Haven't checked what Composer will do in this case.

– Best practice: Always three digits

● Do use alpha, beta, RC for versions undergoing development● Avoid using 0.9.x for development and 1.0.0 for release

– understood as an incompatible change, probably wrong

Page 29: Composer Helpdesk

Adding your library to your own project

● Assume you have tagged your first version 1.0.0– You want to use this version only

composer require fancy-devshop/library:1.0.0– You want to allow updating to later bugfixes

composer require fancy-devshop/library:1.0.*– You want to allow updating to later compatible features

composer require fancy-devshop/library:~1.0

composer require fancy-devshop/library:^1.0.0● How to make your library known to Composer without publishing

it on packagist.org: Wait a few slides.

Page 30: Composer Helpdesk

Version requirements

● When you update all your dependencies, you runcomposer update

● The version requirement affects what may be installed– 1.0.0 → exactly this version

– 1.0.* → any version starting with 1.0 – allows all later patches

– ~1.0 → equivalent to >=1.0, <2.0, allows for compatible updates

– ^1.0.0 → equivalent to >=1.0.0, <2.0, allows for compatible updates

● Not really useful– >=1.0.0 → allows for incompatible updates to versions 2 and beyond

Page 31: Composer Helpdesk

Difference between ~ and ^

● ^ is the newest addition from 2014-12-08– “^1.0.2” → >= 1.0.2, < 2.0, installs at least the patch level mentioned

– “^0.8.1” → >=0.8.1, <0.9, is more defensive with unstable versions

● Doing almost same with ~ isn't the same– “~1.0.2” → => 1.0.2, <1.1 won't include compatible updates

– “~1.0, >=1.0.2” → minimum patch level needs two constraints

– No special case for unstable versions

● Use ~ or ^ for your version requirements!– Unless the external software does not honor semantic versioning.

Page 32: Composer Helpdesk

{ "name": "fancy-devshop/myapplication", "description": "Does useful stuff for everybody.", "license": "proprietary", "authors": [ { "name": "Jane Doe", "email": "[email protected]" } ], "require": { "fancy-devshop/library": "^1.0.2" }, "autoload": { "psr-4": { "Devshop\\: "library/Devshop/" }, "psr-0": { "Devshop_": "library/legacy/" } }}

Page 33: Composer Helpdesk

{ "name": "fancy-devshop/library", "description": "Increases fancyness.", "license": "proprietary", "authors": [ { "name": "Jane Doe", "email": "[email protected]" } ], "require": {}, "autoload": { "psr-4": { "Fancy\\: "src/" } }}

Page 34: Composer Helpdesk

Epic win!

● Our application is using Composer for autoloading, and adding internal and external libraries.

● Our internal library is using Composer for autoloading.– It may use Composer for it's own internal and external dependencies.

● The library has releases that are simply tags in the VCS.● The application can update everything based on version

requirements that SHOULD be compatible to the initial version.– You DO have tests to check if everything works after an update?

Page 35: Composer Helpdesk

What is still missing?

● How to publish your internal libraries without making them public on packagist.org?

● How to develop a library and use a dev version in the application at the same time?

● How to figure out what dependencies and sub-dependencies are really included in a package?

● How to define dependencies that are only used for development?

● What about security?

Page 36: Composer Helpdesk

Publishing the quick way

● Composer by default only asks packagist.org as repository.● You can add your own repository in composer.json:

“repositories”: [

{ “type”: “vcs”, “url”: “ssh://[email protected]” }

]● Composer will then ask for the composer.json in this repo (in all

branches and tags), check whether it has a package name you want to use, and clone or download the correct version.

● Drawback: Does only work at the top level (i.e. your application)– Does not work recursively in libraries you require (with good reasons)

Page 37: Composer Helpdesk

Publishing the easy way

● You need a local instance of either one of these:– Satis (generates static files and dumps downloadable versions)

– Packagist (available for local hosting, dynamic updates)

– Toran Proxy (license costs support Composer development)

● You add this instance location to all your composer.json files“repositories”: [

{ “type”: “composer”,

“url”: “http://fancy-repos.example/satis-files” }

]

Page 38: Composer Helpdesk

Publishing the “easy” way

● You configure your local Packagist clone accordingly.– It should fetch all necessary data from your local repositories.

– It will publish these at the location given.

● Composer will first read from this local repo before going to packagist.org– Works recursively, because the packagist clone is defined at top level

in every package.

– All local packages are known by the clone.

– All external packages are known by packagist.

Page 39: Composer Helpdesk

Satis example

● Satis is available on Github● Configuration example creates downloadable ZIP packages for

each version. Composer will cache these locally.● Run the Satis CLI command every time you need the static files

updated.● Lesser known feature: Composer allows to link to other

composer-repositories

Page 40: Composer Helpdesk

{ "name": "Fancy Devshop", "homepage": "https://fancy-devshop.example/satis-files", "repositories": [ { "type": "vcs", "url": "ssh://[email protected]:2222/repos/library.git" }, { "type": "composer", "url": "https://fancy-devshop.example/released-fairy-dust" }

], "require-all": true, "archive": { "directory": "dist", "format": "zip", "prefix-url": "https://fancy-devshop.example/satis-files", "skip-dev": true }, "twig-template": "views/index-fancy.html.twig"}

Page 41: Composer Helpdesk

Epic win!

● The application's dependencies can be loaded from the local Satis or from Packagist.

● New versions of local libraries will be detected and published locally (manually, with a cronjob, with a repo hook).

● This should be all you need to finally be able to deploy!– I won't go into deployment details now, but as a hint:

composer install --no-dev

Page 42: Composer Helpdesk

How to use a package under development?

● Tagging every single commit is not helpful.● Add a branch with a version alias

composer require \

"fancy-devshop/library:dev-master as 2.0.0-dev"● Or create a branch resembling the target version

git branch 2.0.x

composer require "fancy-devshop/library:~2.0@dev"– Update regularly

composer update● Upgrade the version requirement after release.

Page 43: Composer Helpdesk

How to get an overview of used packages?

● The composer.lock file has every package and version recorded that is being used. Always commit this file!

● Reading it isn't nice, but you can see some details.● What about a picture? Use clue/graph-composer ● Needs graphviz installed to render the pictures.● Shows all the dependencies and version requirements.

Page 44: Composer Helpdesk
Page 45: Composer Helpdesk
Page 46: Composer Helpdesk

How to treat code used for development only?

● Add stuff like PHPUnit, Mockery, as a dev dependencycomposer require --dev phpunit/phpunit:~4.4

● Add your own development code as dev autoloading:“autoload-dev”: {

“psr-4”: { “Tests\\”: “tests/helpers/” }

}● This will not be added or installed when you run with --no-dev

Page 47: Composer Helpdesk

Security considerations

● Composer currently has no code signing or security layer!● There is some security coming from GIT commit ids and using

HTTPS.● Assume everything outside your own environment is

compromised and broken if you really have sensitive applications that undergo audits.

● Think about cloning external software into local repos, then treating them as local software.

● You can disable using Packagist in composer.json“repositories”: [ { “packagist”: false } ]

Page 48: Composer Helpdesk

Thank you!

● And now it's time for all your questions!

● Slides will be online soon.

● Contact me or ask questions here:– Twitter: @SvenRtbg

– StackOverflow: Sven