DOWNGRADE

and Other Composer Tricks

TO

upgrade

Before WE Begin...

Slides/Code/Resources

Rate This Talk

joind.in/talk/970b2
wkdb.yt/downgrade
wkdb.yt/downgrade
  • Contract PHP Developer and Consultant
  • Never Intended to Be a Developer
  • Currently Living in Dallas w/ Wife and Dog

Hello, World...

wkdb.yt/downgrade

I've spent the last year-and-half focused on upgrading a massive monolithic code base with ~300 dependencies from PHP 7.4 to PHP 8.2

Hello, World...

Surviving

And Open Source Maintainer's Bad Decisions

Version

conflicts

wkdb.yt/downgrade

Making Assumptions / Setting Expectations

That you have a basic, working familiarity with Composer, and have used it to install and update project dependencies from the command line; and at some point have been faced with a version conflict:

A.

wkdb.yt/downgrade

Making Assumptions / Setting Expectations

That you understand that these are tricks and workarounds for dealing with nasty edge cases and difficult upgrade situations -- and probably things you should avoid doing if you there are better upgrade options

B.

  • How large and how "legacy" is the code base?
  • How many packages are installed?
  • How many of those are outdated by more than one major version?
  • How big of a version jump are you making?
  • Do you need to run multiple versions simultaneously?
wkdb.yt/downgrade

Composer Dependency Management 101

Why Does This Keep Happening To Me?

wkdb.yt/downgrade

Root

Direct Dependency

Transitive Dependency

Composer Dependency Management 101

Transitive Dependencies of Dependencies

wkdb.yt/downgrade

Composer Dependency Management 101

{
    "name": "laravel/laravel",
    "type": "project",
    "description": "The skeleton application for the Laravel framework.",
    "keywords": ["laravel", "framework"],
    "license": "MIT",
    "require": {
        "php": "^8.1",
        "guzzlehttp/guzzle": "^7.2",
        "laravel/framework": "^10.10",
        "laravel/sanctum": "^3.3",
        "laravel/tinker": "^2.8"
    },
    "require-dev": {
        "fakerphp/faker": "^1.9.1",
        "laravel/pint": "^1.0",
        "laravel/sail": "^1.18",
        "mockery/mockery": "^1.4.4",
        "nunomaduro/collision": "^7.0",
        "phpunit/phpunit": "^10.1",
        "spatie/laravel-ignition": "^2.0"
    },
    "autoload": {
        "psr-4": {
            "App\\": "app/",
            "Database\\Factories\\": "database/factories/",
            "Database\\Seeders\\": "database/seeders/"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "Tests\\": "tests/"
        }
    },
    "scripts": {
        "post-autoload-dump": [
            "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
            "@php artisan package:discover --ansi"
        ],
        "post-update-cmd": [
            "@php artisan vendor:publish --tag=laravel-assets --ansi --force"
        ],
        "post-root-package-install": [
            "@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
        ],
        "post-create-project-cmd": [
            "@php artisan key:generate --ansi"
        ]
    },
    "extra": {
        "laravel": {
            "dont-discover": []
        }
    },
    "config": {
        "optimize-autoloader": true,
        "preferred-install": "dist",
        "sort-packages": true,
        "allow-plugins": {
            "pestphp/pest-plugin": true,
            "php-http/discovery": true
        }
    },
    "minimum-stability": "stable",
    "prefer-stable": true
}

Composer Dependency Management 101

wkdb.yt/downgrade
wkdb.yt/downgrade
brick/math
dflydev/dot-access-data
doctrine/inflector
doctrine/lexer
dragonmantank/cron-expression
egulias/email-validator
fakerphp/faker
filp/whoops
fruitcake/php-cors
graham-campbell/result-type
guzzlehttp/guzzle
guzzlehttp/promises
guzzlehttp/psr7
guzzlehttp/uri-template
hamcrest/hamcrest-php
laravel/framework
laravel/pint
laravel/prompts
laravel/sail
laravel/sanctum
laravel/serializable-closure
laravel/tinker
league/commonmark
league/config
league/flysystem
league/flysystem-local
league/mime-type-detection
mockery/mockery
monolog/monolog
myclabs/deep-copy
nesbot/carbon
nette/schema
nette/utils
nikic/php-parser
nunomaduro/collision
nunomaduro/termwind
phar-io/manifest
phar-io/version
phpoption/phpoption
phpunit/php-code-coverage
phpunit/php-file-iterator
phpunit/php-invoker
phpunit/php-text-template
phpunit/php-timer
phpunit/phpunit
psr/clock
psr/container
psr/event-dispatcher
psr/http-client
psr/http-factory
psr/http-message
psr/log
psr/simple-cache
psy/psysh
ralouphie/getallheaders
ramsey/collection

ramsey/uuid
sebastian/cli-parser
sebastian/code-unit
sebastian/code-unit-reverse-lookup
sebastian/comparator
sebastian/complexity
sebastian/diff
sebastian/environment
sebastian/exporter
sebastian/global-state
sebastian/lines-of-code
sebastian/object-enumerator
sebastian/object-reflector
sebastian/recursion-context
sebastian/type
sebastian/version
spatie/backtrace
spatie/flare-client-php
spatie/ignition
spatie/laravel-ignition
symfony/console
symfony/css-selector
symfony/deprecation-contracts
symfony/error-handler
symfony/event-dispatcher
symfony/event-dispatcher-contracts
symfony/finder
symfony/http-foundation
symfony/http-kernel
symfony/mailer
symfony/mime
symfony/polyfill-ctype
symfony/polyfill-intl-grapheme
symfony/polyfill-intl-idn
symfony/polyfill-intl-normalizer
symfony/polyfill-mbstring
symfony/polyfill-php72
symfony/polyfill-php80
symfony/polyfill-php83
symfony/polyfill-uuid
symfony/process
symfony/routing
symfony/service-contracts
symfony/string
symfony/translation
symfony/translation-contracts
symfony/uid
symfony/var-dumper
symfony/yaml
theseer/tokenizer
tijsverkoyen/css-to-inline-styles
vlucas/phpdotenv
voku/portable-ascii
webmozart/assert

1 Root | 12 Direct | 98 Transitive

Composer Dependency Management 101

wkdb.yt/downgrade

Composer Dependency Management 101

wkdb.yt/downgrade

Composer Dependency Management 201

Sometimes, conflict Is Hard To Resolve

wkdb.yt/downgrade

We Need Some Tricks To Deal With...

- The "Please Don't Make Me Install This" Dependency

- The "Please Tag A New Release" Dependency

- The "Please Merge My Pull Request" Lagging Dependency

- The "Please Don't Leave Me Behind" Leading Dependency

wkdb.yt/downgrade

Live Coding Examples

wkdb.yt/downgrade

Avoiding This In The First Place

Prevention Costs Less Than the Cure

But You May Still Need To Convince Management

wkdb.yt/downgrade

Avoiding This In The First Place

1. If you don't need it, don't install it. If You Do Need It, Keep It UpDated

Be mindful not only about what you add to your "composer.json" file and any new transitive dependencies introduced.

If you do require a package, keep it and its dependencies up to date

wkdb.yt/downgrade

Avoiding This In The First Place

2. Embrace The Adapter Pattern

TL;DR: Instead of directly using classes provided by third party packages (other than framework and "universal" packages) throughout your code, isolate the usage to a single place by defining your own interfaces and implementations that "wrap" the third-party code.

 

wkdb.yt/downgrade

Avoiding This In The First Place

3. "Frameworkless" PHP IS Great, but Pick a FrameWork

But, if your project uses a bunch of components from Symfony, Laravel, Laminas, CakePHP, and WordPress, you're going to have a bad time.

It's fine to have a project based on a framework like Symfony or Laravel that also uses components from open source libraries, or to use components from a framework and other open source libraries.

wkdb.yt/downgrade

Questions?

https://joind.in/talk/970b2
Email: andy@wickedbyte.com
Twitter: @andrewsnell
GitHub/Discord: andysnell

Downgrade to Upgrade and Other Composer Tricks

By Andy Snell

Downgrade to Upgrade and Other Composer Tricks

Thanks to the ubiquity of Composer, a PHP application may depend on dozens of third-party packages, each of which will define their own dependencies. When an application is deployed and working as expected, it can be difficult to prioritize the development time for package updates with breaking changes, and you might find some dependencies have slipped a few major versions behind their current release. Nevertheless, even if all root dependencies are up to date, some packages inevitably become abandoned, drop version constraints, or add an incompatible dependency. The end result: upgrading to the latest PHP version (or other package) is blocked by a tangled web of interdependent version conflicts and incompatible vendor code.

  • 126