From 75991152a8f7a091c412cde10daac1ae18a39267 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Mon, 3 Mar 2025 11:58:12 +0100 Subject: [PATCH 1/2] [post] strangle antipattern --- composer.lock | 405 +++++++++--------- ...your-project-with-strangle-anti-pattern.md | 109 +++++ resources/views/blog/blog.blade.php | 10 +- resources/views/blog/post.blade.php | 4 +- resources/views/homepage/contact.blade.php | 4 +- src/Controller/Blog/BlogController.php | 2 +- 6 files changed, 317 insertions(+), 217 deletions(-) create mode 100644 resources/blog/posts/2025/2025-03-03-how-to-strangle-your-project-with-strangle-anti-pattern.md diff --git a/composer.lock b/composer.lock index de46e3df0..444e8664c 100644 --- a/composer.lock +++ b/composer.lock @@ -8,16 +8,16 @@ "packages": [ { "name": "brick/math", - "version": "0.12.1", + "version": "0.12.3", "source": { "type": "git", "url": "https://github.com/brick/math.git", - "reference": "f510c0a40911935b77b86859eb5223d58d660df1" + "reference": "866551da34e9a618e64a819ee1e01c20d8a588ba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/brick/math/zipball/f510c0a40911935b77b86859eb5223d58d660df1", - "reference": "f510c0a40911935b77b86859eb5223d58d660df1", + "url": "https://api.github.com/repos/brick/math/zipball/866551da34e9a618e64a819ee1e01c20d8a588ba", + "reference": "866551da34e9a618e64a819ee1e01c20d8a588ba", "shasum": "" }, "require": { @@ -26,7 +26,7 @@ "require-dev": { "php-coveralls/php-coveralls": "^2.2", "phpunit/phpunit": "^10.1", - "vimeo/psalm": "5.16.0" + "vimeo/psalm": "6.8.8" }, "type": "library", "autoload": { @@ -56,7 +56,7 @@ ], "support": { "issues": "https://github.com/brick/math/issues", - "source": "https://github.com/brick/math/tree/0.12.1" + "source": "https://github.com/brick/math/tree/0.12.3" }, "funding": [ { @@ -64,7 +64,7 @@ "type": "github" } ], - "time": "2023-11-29T23:19:16+00:00" + "time": "2025-02-28T13:11:00+00:00" }, { "name": "carbonphp/carbon-doctrine-types", @@ -1018,16 +1018,16 @@ }, { "name": "guzzlehttp/uri-template", - "version": "v1.0.3", + "version": "v1.0.4", "source": { "type": "git", "url": "https://github.com/guzzle/uri-template.git", - "reference": "ecea8feef63bd4fef1f037ecb288386999ecc11c" + "reference": "30e286560c137526eccd4ce21b2de477ab0676d2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/uri-template/zipball/ecea8feef63bd4fef1f037ecb288386999ecc11c", - "reference": "ecea8feef63bd4fef1f037ecb288386999ecc11c", + "url": "https://api.github.com/repos/guzzle/uri-template/zipball/30e286560c137526eccd4ce21b2de477ab0676d2", + "reference": "30e286560c137526eccd4ce21b2de477ab0676d2", "shasum": "" }, "require": { @@ -1084,7 +1084,7 @@ ], "support": { "issues": "https://github.com/guzzle/uri-template/issues", - "source": "https://github.com/guzzle/uri-template/tree/v1.0.3" + "source": "https://github.com/guzzle/uri-template/tree/v1.0.4" }, "funding": [ { @@ -1100,7 +1100,7 @@ "type": "tidelift" } ], - "time": "2023-12-03T19:50:20+00:00" + "time": "2025-02-03T10:55:03+00:00" }, { "name": "imagine/imagine", @@ -1215,16 +1215,16 @@ }, { "name": "laravel/framework", - "version": "v11.39.1", + "version": "v11.44.0", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "3d693dd36e78121bcd51fc02eda4bc137d2a17f2" + "reference": "e9a33da34815ac1ed46c7e4c477a775f4592f0a7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/3d693dd36e78121bcd51fc02eda4bc137d2a17f2", - "reference": "3d693dd36e78121bcd51fc02eda4bc137d2a17f2", + "url": "https://api.github.com/repos/laravel/framework/zipball/e9a33da34815ac1ed46c7e4c477a775f4592f0a7", + "reference": "e9a33da34815ac1ed46c7e4c477a775f4592f0a7", "shasum": "" }, "require": { @@ -1250,7 +1250,7 @@ "league/flysystem-local": "^3.25.1", "league/uri": "^7.5.1", "monolog/monolog": "^3.0", - "nesbot/carbon": "^2.72.2|^3.4", + "nesbot/carbon": "^2.72.6|^3.8.4", "nunomaduro/termwind": "^2.0", "php": "^8.2", "psr/container": "^1.1.1|^2.0.1", @@ -1325,17 +1325,18 @@ "fakerphp/faker": "^1.24", "guzzlehttp/promises": "^2.0.3", "guzzlehttp/psr7": "^2.4", + "laravel/pint": "^1.18", "league/flysystem-aws-s3-v3": "^3.25.1", "league/flysystem-ftp": "^3.25.1", "league/flysystem-path-prefixing": "^3.25.1", "league/flysystem-read-only": "^3.25.1", "league/flysystem-sftp-v3": "^3.25.1", "mockery/mockery": "^1.6.10", - "orchestra/testbench-core": "^9.6", + "orchestra/testbench-core": "^9.9.4", "pda/pheanstalk": "^5.0.6", "php-http/discovery": "^1.15", - "phpstan/phpstan": "^1.11.5", - "phpunit/phpunit": "^10.5.35|^11.3.6", + "phpstan/phpstan": "^2.0", + "phpunit/phpunit": "^10.5.35|^11.3.6|^12.0.1", "predis/predis": "^2.3", "resend/resend-php": "^0.10.0", "symfony/cache": "^7.0.3", @@ -1367,7 +1368,7 @@ "mockery/mockery": "Required to use mocking (^1.6).", "pda/pheanstalk": "Required to use the beanstalk queue driver (^5.0).", "php-http/discovery": "Required to use PSR-7 bridging features (^1.15).", - "phpunit/phpunit": "Required to use assertions and run tests (^10.5|^11.0).", + "phpunit/phpunit": "Required to use assertions and run tests (^10.5.35|^11.3.6|^12.0.1).", "predis/predis": "Required to use the predis connector (^2.3).", "psr/http-message": "Required to allow Storage::put to accept a StreamInterface (^1.0).", "pusher/pusher-php-server": "Required to use the Pusher broadcast driver (^6.0|^7.0).", @@ -1425,20 +1426,20 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2025-01-22T17:01:46+00:00" + "time": "2025-02-24T13:08:54+00:00" }, { "name": "laravel/prompts", - "version": "v0.3.3", + "version": "v0.3.5", "source": { "type": "git", "url": "https://github.com/laravel/prompts.git", - "reference": "749395fcd5f8f7530fe1f00dfa84eb22c83d94ea" + "reference": "57b8f7efe40333cdb925700891c7d7465325d3b1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/prompts/zipball/749395fcd5f8f7530fe1f00dfa84eb22c83d94ea", - "reference": "749395fcd5f8f7530fe1f00dfa84eb22c83d94ea", + "url": "https://api.github.com/repos/laravel/prompts/zipball/57b8f7efe40333cdb925700891c7d7465325d3b1", + "reference": "57b8f7efe40333cdb925700891c7d7465325d3b1", "shasum": "" }, "require": { @@ -1452,7 +1453,7 @@ "laravel/framework": ">=10.17.0 <10.25.0" }, "require-dev": { - "illuminate/collections": "^10.0|^11.0", + "illuminate/collections": "^10.0|^11.0|^12.0", "mockery/mockery": "^1.5", "pestphp/pest": "^2.3|^3.4", "phpstan/phpstan": "^1.11", @@ -1482,31 +1483,31 @@ "description": "Add beautiful and user-friendly forms to your command-line applications.", "support": { "issues": "https://github.com/laravel/prompts/issues", - "source": "https://github.com/laravel/prompts/tree/v0.3.3" + "source": "https://github.com/laravel/prompts/tree/v0.3.5" }, - "time": "2024-12-30T15:53:31+00:00" + "time": "2025-02-11T13:34:40+00:00" }, { "name": "laravel/serializable-closure", - "version": "v2.0.1", + "version": "v2.0.3", "source": { "type": "git", "url": "https://github.com/laravel/serializable-closure.git", - "reference": "613b2d4998f85564d40497e05e89cb6d9bd1cbe8" + "reference": "f379c13663245f7aa4512a7869f62eb14095f23f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/613b2d4998f85564d40497e05e89cb6d9bd1cbe8", - "reference": "613b2d4998f85564d40497e05e89cb6d9bd1cbe8", + "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/f379c13663245f7aa4512a7869f62eb14095f23f", + "reference": "f379c13663245f7aa4512a7869f62eb14095f23f", "shasum": "" }, "require": { "php": "^8.1" }, "require-dev": { - "illuminate/support": "^10.0|^11.0", + "illuminate/support": "^10.0|^11.0|^12.0", "nesbot/carbon": "^2.67|^3.0", - "pestphp/pest": "^2.36", + "pestphp/pest": "^2.36|^3.0", "phpstan/phpstan": "^2.0", "symfony/var-dumper": "^6.2.0|^7.0.0" }, @@ -1545,7 +1546,7 @@ "issues": "https://github.com/laravel/serializable-closure/issues", "source": "https://github.com/laravel/serializable-closure" }, - "time": "2024-12-16T15:26:28+00:00" + "time": "2025-02-11T15:03:05+00:00" }, { "name": "league/commonmark", @@ -2100,23 +2101,23 @@ }, { "name": "livewire/livewire", - "version": "v3.5.18", + "version": "v3.6.0", "source": { "type": "git", "url": "https://github.com/livewire/livewire.git", - "reference": "62f0fa6b340a467c25baa590a567d9a134b357da" + "reference": "4c66b569cb729ba9b2f4a3c4e79f50fd8f2b71d1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/livewire/livewire/zipball/62f0fa6b340a467c25baa590a567d9a134b357da", - "reference": "62f0fa6b340a467c25baa590a567d9a134b357da", + "url": "https://api.github.com/repos/livewire/livewire/zipball/4c66b569cb729ba9b2f4a3c4e79f50fd8f2b71d1", + "reference": "4c66b569cb729ba9b2f4a3c4e79f50fd8f2b71d1", "shasum": "" }, "require": { - "illuminate/database": "^10.0|^11.0", - "illuminate/routing": "^10.0|^11.0", - "illuminate/support": "^10.0|^11.0", - "illuminate/validation": "^10.0|^11.0", + "illuminate/database": "^10.0|^11.0|^12.0", + "illuminate/routing": "^10.0|^11.0|^12.0", + "illuminate/support": "^10.0|^11.0|^12.0", + "illuminate/validation": "^10.0|^11.0|^12.0", "laravel/prompts": "^0.1.24|^0.2|^0.3", "league/mime-type-detection": "^1.9", "php": "^8.1", @@ -2125,11 +2126,11 @@ }, "require-dev": { "calebporzio/sushi": "^2.1", - "laravel/framework": "^10.15.0|^11.0", + "laravel/framework": "^10.15.0|^11.0|^12.0", "mockery/mockery": "^1.3.1", - "orchestra/testbench": "^8.21.0|^9.0", - "orchestra/testbench-dusk": "^8.24|^9.1", - "phpunit/phpunit": "^10.4", + "orchestra/testbench": "^8.21.0|^9.0|^10.0", + "orchestra/testbench-dusk": "^8.24|^9.1|^10.0", + "phpunit/phpunit": "^10.4|^11.5", "psy/psysh": "^0.11.22|^0.12" }, "type": "library", @@ -2164,7 +2165,7 @@ "description": "A front-end framework for Laravel.", "support": { "issues": "https://github.com/livewire/livewire/issues", - "source": "https://github.com/livewire/livewire/tree/v3.5.18" + "source": "https://github.com/livewire/livewire/tree/v3.6.0" }, "funding": [ { @@ -2172,7 +2173,7 @@ "type": "github" } ], - "time": "2024-12-23T15:05:02+00:00" + "time": "2025-02-26T00:57:32+00:00" }, { "name": "monolog/monolog", @@ -2279,16 +2280,16 @@ }, { "name": "nesbot/carbon", - "version": "3.8.4", + "version": "3.8.6", "source": { "type": "git", "url": "https://github.com/CarbonPHP/carbon.git", - "reference": "129700ed449b1f02d70272d2ac802357c8c30c58" + "reference": "ff2f20cf83bd4d503720632ce8a426dc747bf7fd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/129700ed449b1f02d70272d2ac802357c8c30c58", - "reference": "129700ed449b1f02d70272d2ac802357c8c30c58", + "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/ff2f20cf83bd4d503720632ce8a426dc747bf7fd", + "reference": "ff2f20cf83bd4d503720632ce8a426dc747bf7fd", "shasum": "" }, "require": { @@ -2364,8 +2365,8 @@ ], "support": { "docs": "https://carbon.nesbot.com/docs", - "issues": "https://github.com/briannesbitt/Carbon/issues", - "source": "https://github.com/briannesbitt/Carbon" + "issues": "https://github.com/CarbonPHP/carbon/issues", + "source": "https://github.com/CarbonPHP/carbon" }, "funding": [ { @@ -2381,7 +2382,7 @@ "type": "tidelift" } ], - "time": "2024-12-27T09:25:35+00:00" + "time": "2025-02-20T17:33:38+00:00" }, { "name": "nette/schema", @@ -3267,16 +3268,16 @@ }, { "name": "ramsey/collection", - "version": "2.0.0", + "version": "2.1.0", "source": { "type": "git", "url": "https://github.com/ramsey/collection.git", - "reference": "a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5" + "reference": "3c5990b8a5e0b79cd1cf11c2dc1229e58e93f109" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/collection/zipball/a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5", - "reference": "a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5", + "url": "https://api.github.com/repos/ramsey/collection/zipball/3c5990b8a5e0b79cd1cf11c2dc1229e58e93f109", + "reference": "3c5990b8a5e0b79cd1cf11c2dc1229e58e93f109", "shasum": "" }, "require": { @@ -3284,25 +3285,22 @@ }, "require-dev": { "captainhook/plugin-composer": "^5.3", - "ergebnis/composer-normalize": "^2.28.3", - "fakerphp/faker": "^1.21", + "ergebnis/composer-normalize": "^2.45", + "fakerphp/faker": "^1.24", "hamcrest/hamcrest-php": "^2.0", - "jangregor/phpstan-prophecy": "^1.0", - "mockery/mockery": "^1.5", + "jangregor/phpstan-prophecy": "^2.1", + "mockery/mockery": "^1.6", "php-parallel-lint/php-console-highlighter": "^1.0", - "php-parallel-lint/php-parallel-lint": "^1.3", - "phpcsstandards/phpcsutils": "^1.0.0-rc1", - "phpspec/prophecy-phpunit": "^2.0", - "phpstan/extension-installer": "^1.2", - "phpstan/phpstan": "^1.9", - "phpstan/phpstan-mockery": "^1.1", - "phpstan/phpstan-phpunit": "^1.3", - "phpunit/phpunit": "^9.5", - "psalm/plugin-mockery": "^1.1", - "psalm/plugin-phpunit": "^0.18.4", - "ramsey/coding-standard": "^2.0.3", - "ramsey/conventional-commits": "^1.3", - "vimeo/psalm": "^5.4" + "php-parallel-lint/php-parallel-lint": "^1.4", + "phpspec/prophecy-phpunit": "^2.3", + "phpstan/extension-installer": "^1.4", + "phpstan/phpstan": "^2.1", + "phpstan/phpstan-mockery": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpunit/phpunit": "^10.5", + "ramsey/coding-standard": "^2.3", + "ramsey/conventional-commits": "^1.6", + "roave/security-advisories": "dev-latest" }, "type": "library", "extra": { @@ -3340,19 +3338,9 @@ ], "support": { "issues": "https://github.com/ramsey/collection/issues", - "source": "https://github.com/ramsey/collection/tree/2.0.0" + "source": "https://github.com/ramsey/collection/tree/2.1.0" }, - "funding": [ - { - "url": "https://github.com/ramsey", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/ramsey/collection", - "type": "tidelift" - } - ], - "time": "2022-12-31T21:50:55+00:00" + "time": "2025-03-02T04:48:29+00:00" }, { "name": "ramsey/uuid", @@ -3452,12 +3440,12 @@ "source": { "type": "git", "url": "https://github.com/rectorphp/rector.git", - "reference": "8d61334bb35438652b586dca5786cacbec98c2bb" + "reference": "8ae64fb5fc95d296a28b5ae198d5d7b8ccfb6bb1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/rectorphp/rector/zipball/8d61334bb35438652b586dca5786cacbec98c2bb", - "reference": "8d61334bb35438652b586dca5786cacbec98c2bb", + "url": "https://api.github.com/repos/rectorphp/rector/zipball/8ae64fb5fc95d296a28b5ae198d5d7b8ccfb6bb1", + "reference": "8ae64fb5fc95d296a28b5ae198d5d7b8ccfb6bb1", "shasum": "" }, "require": { @@ -3504,7 +3492,7 @@ "type": "github" } ], - "time": "2025-03-02T15:33:53+00:00" + "time": "2025-03-03T09:16:46+00:00" }, { "name": "samsonasik/array-lookup", @@ -3873,16 +3861,16 @@ }, { "name": "symfony/error-handler", - "version": "v7.2.1", + "version": "v7.2.4", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "6150b89186573046167796fa5f3f76601d5145f8" + "reference": "aabf79938aa795350c07ce6464dd1985607d95d5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/6150b89186573046167796fa5f3f76601d5145f8", - "reference": "6150b89186573046167796fa5f3f76601d5145f8", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/aabf79938aa795350c07ce6464dd1985607d95d5", + "reference": "aabf79938aa795350c07ce6464dd1985607d95d5", "shasum": "" }, "require": { @@ -3928,7 +3916,7 @@ "description": "Provides tools to manage errors and ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/error-handler/tree/v7.2.1" + "source": "https://github.com/symfony/error-handler/tree/v7.2.4" }, "funding": [ { @@ -3944,7 +3932,7 @@ "type": "tidelift" } ], - "time": "2024-12-07T08:50:44+00:00" + "time": "2025-02-02T20:27:07+00:00" }, { "name": "symfony/event-dispatcher", @@ -4234,16 +4222,16 @@ }, { "name": "symfony/http-foundation", - "version": "v7.2.2", + "version": "v7.2.3", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "62d1a43796ca3fea3f83a8470dfe63a4af3bc588" + "reference": "ee1b504b8926198be89d05e5b6fc4c3810c090f0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/62d1a43796ca3fea3f83a8470dfe63a4af3bc588", - "reference": "62d1a43796ca3fea3f83a8470dfe63a4af3bc588", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/ee1b504b8926198be89d05e5b6fc4c3810c090f0", + "reference": "ee1b504b8926198be89d05e5b6fc4c3810c090f0", "shasum": "" }, "require": { @@ -4292,7 +4280,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v7.2.2" + "source": "https://github.com/symfony/http-foundation/tree/v7.2.3" }, "funding": [ { @@ -4308,20 +4296,20 @@ "type": "tidelift" } ], - "time": "2024-12-30T19:00:17+00:00" + "time": "2025-01-17T10:56:55+00:00" }, { "name": "symfony/http-kernel", - "version": "v7.2.2", + "version": "v7.2.4", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "3c432966bd8c7ec7429663105f5a02d7e75b4306" + "reference": "9f1103734c5789798fefb90e91de4586039003ed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/3c432966bd8c7ec7429663105f5a02d7e75b4306", - "reference": "3c432966bd8c7ec7429663105f5a02d7e75b4306", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/9f1103734c5789798fefb90e91de4586039003ed", + "reference": "9f1103734c5789798fefb90e91de4586039003ed", "shasum": "" }, "require": { @@ -4406,7 +4394,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v7.2.2" + "source": "https://github.com/symfony/http-kernel/tree/v7.2.4" }, "funding": [ { @@ -4422,20 +4410,20 @@ "type": "tidelift" } ], - "time": "2024-12-31T14:59:40+00:00" + "time": "2025-02-26T11:01:22+00:00" }, { "name": "symfony/mailer", - "version": "v7.2.0", + "version": "v7.2.3", "source": { "type": "git", "url": "https://github.com/symfony/mailer.git", - "reference": "e4d358702fb66e4c8a2af08e90e7271a62de39cc" + "reference": "f3871b182c44997cf039f3b462af4a48fb85f9d3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mailer/zipball/e4d358702fb66e4c8a2af08e90e7271a62de39cc", - "reference": "e4d358702fb66e4c8a2af08e90e7271a62de39cc", + "url": "https://api.github.com/repos/symfony/mailer/zipball/f3871b182c44997cf039f3b462af4a48fb85f9d3", + "reference": "f3871b182c44997cf039f3b462af4a48fb85f9d3", "shasum": "" }, "require": { @@ -4486,7 +4474,7 @@ "description": "Helps sending emails", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/mailer/tree/v7.2.0" + "source": "https://github.com/symfony/mailer/tree/v7.2.3" }, "funding": [ { @@ -4502,20 +4490,20 @@ "type": "tidelift" } ], - "time": "2024-11-25T15:21:05+00:00" + "time": "2025-01-27T11:08:17+00:00" }, { "name": "symfony/mime", - "version": "v7.2.1", + "version": "v7.2.4", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "7f9617fcf15cb61be30f8b252695ed5e2bfac283" + "reference": "87ca22046b78c3feaff04b337f33b38510fd686b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/7f9617fcf15cb61be30f8b252695ed5e2bfac283", - "reference": "7f9617fcf15cb61be30f8b252695ed5e2bfac283", + "url": "https://api.github.com/repos/symfony/mime/zipball/87ca22046b78c3feaff04b337f33b38510fd686b", + "reference": "87ca22046b78c3feaff04b337f33b38510fd686b", "shasum": "" }, "require": { @@ -4570,7 +4558,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v7.2.1" + "source": "https://github.com/symfony/mime/tree/v7.2.4" }, "funding": [ { @@ -4586,7 +4574,7 @@ "type": "tidelift" } ], - "time": "2024-12-07T08:50:44+00:00" + "time": "2025-02-19T08:51:20+00:00" }, { "name": "symfony/polyfill-ctype", @@ -5226,16 +5214,16 @@ }, { "name": "symfony/process", - "version": "v7.2.0", + "version": "v7.2.4", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "d34b22ba9390ec19d2dd966c40aa9e8462f27a7e" + "reference": "d8f411ff3c7ddc4ae9166fb388d1190a2df5b5cf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/d34b22ba9390ec19d2dd966c40aa9e8462f27a7e", - "reference": "d34b22ba9390ec19d2dd966c40aa9e8462f27a7e", + "url": "https://api.github.com/repos/symfony/process/zipball/d8f411ff3c7ddc4ae9166fb388d1190a2df5b5cf", + "reference": "d8f411ff3c7ddc4ae9166fb388d1190a2df5b5cf", "shasum": "" }, "require": { @@ -5267,7 +5255,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v7.2.0" + "source": "https://github.com/symfony/process/tree/v7.2.4" }, "funding": [ { @@ -5283,20 +5271,20 @@ "type": "tidelift" } ], - "time": "2024-11-06T14:24:19+00:00" + "time": "2025-02-05T08:33:46+00:00" }, { "name": "symfony/routing", - "version": "v7.2.0", + "version": "v7.2.3", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "e10a2450fa957af6c448b9b93c9010a4e4c0725e" + "reference": "ee9a67edc6baa33e5fae662f94f91fd262930996" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/e10a2450fa957af6c448b9b93c9010a4e4c0725e", - "reference": "e10a2450fa957af6c448b9b93c9010a4e4c0725e", + "url": "https://api.github.com/repos/symfony/routing/zipball/ee9a67edc6baa33e5fae662f94f91fd262930996", + "reference": "ee9a67edc6baa33e5fae662f94f91fd262930996", "shasum": "" }, "require": { @@ -5348,7 +5336,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v7.2.0" + "source": "https://github.com/symfony/routing/tree/v7.2.3" }, "funding": [ { @@ -5364,7 +5352,7 @@ "type": "tidelift" } ], - "time": "2024-11-25T11:08:51+00:00" + "time": "2025-01-17T10:56:55+00:00" }, { "name": "symfony/service-contracts", @@ -5538,16 +5526,16 @@ }, { "name": "symfony/translation", - "version": "v7.2.2", + "version": "v7.2.4", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "e2674a30132b7cc4d74540d6c2573aa363f05923" + "reference": "283856e6981286cc0d800b53bd5703e8e363f05a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/e2674a30132b7cc4d74540d6c2573aa363f05923", - "reference": "e2674a30132b7cc4d74540d6c2573aa363f05923", + "url": "https://api.github.com/repos/symfony/translation/zipball/283856e6981286cc0d800b53bd5703e8e363f05a", + "reference": "283856e6981286cc0d800b53bd5703e8e363f05a", "shasum": "" }, "require": { @@ -5613,7 +5601,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v7.2.2" + "source": "https://github.com/symfony/translation/tree/v7.2.4" }, "funding": [ { @@ -5629,7 +5617,7 @@ "type": "tidelift" } ], - "time": "2024-12-07T08:18:10+00:00" + "time": "2025-02-13T10:27:23+00:00" }, { "name": "symfony/translation-contracts", @@ -5785,16 +5773,16 @@ }, { "name": "symfony/var-dumper", - "version": "v7.2.0", + "version": "v7.2.3", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "c6a22929407dec8765d6e2b6ff85b800b245879c" + "reference": "82b478c69745d8878eb60f9a049a4d584996f73a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/c6a22929407dec8765d6e2b6ff85b800b245879c", - "reference": "c6a22929407dec8765d6e2b6ff85b800b245879c", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/82b478c69745d8878eb60f9a049a4d584996f73a", + "reference": "82b478c69745d8878eb60f9a049a4d584996f73a", "shasum": "" }, "require": { @@ -5848,7 +5836,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v7.2.0" + "source": "https://github.com/symfony/var-dumper/tree/v7.2.3" }, "funding": [ { @@ -5864,20 +5852,20 @@ "type": "tidelift" } ], - "time": "2024-11-08T15:48:14+00:00" + "time": "2025-01-17T11:39:41+00:00" }, { "name": "symfony/yaml", - "version": "v7.2.0", + "version": "v7.2.3", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "099581e99f557e9f16b43c5916c26380b54abb22" + "reference": "ac238f173df0c9c1120f862d0f599e17535a87ec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/099581e99f557e9f16b43c5916c26380b54abb22", - "reference": "099581e99f557e9f16b43c5916c26380b54abb22", + "url": "https://api.github.com/repos/symfony/yaml/zipball/ac238f173df0c9c1120f862d0f599e17535a87ec", + "reference": "ac238f173df0c9c1120f862d0f599e17535a87ec", "shasum": "" }, "require": { @@ -5920,7 +5908,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v7.2.0" + "source": "https://github.com/symfony/yaml/tree/v7.2.3" }, "funding": [ { @@ -5936,20 +5924,20 @@ "type": "tidelift" } ], - "time": "2024-10-23T06:56:12+00:00" + "time": "2025-01-07T12:55:42+00:00" }, { "name": "symplify/vendor-patches", - "version": "11.3.7", + "version": "11.4.1", "source": { "type": "git", "url": "https://github.com/symplify/vendor-patches.git", - "reference": "dec8ec588192a3ee0d886288395b5cd6a768126e" + "reference": "085a3a3e456e4d2d9a6b4fe02e86f92ce5b1fe35" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symplify/vendor-patches/zipball/dec8ec588192a3ee0d886288395b5cd6a768126e", - "reference": "dec8ec588192a3ee0d886288395b5cd6a768126e", + "url": "https://api.github.com/repos/symplify/vendor-patches/zipball/085a3a3e456e4d2d9a6b4fe02e86f92ce5b1fe35", + "reference": "085a3a3e456e4d2d9a6b4fe02e86f92ce5b1fe35", "shasum": "" }, "require": { @@ -5967,7 +5955,7 @@ "description": "Generate vendor patches for packages with single command", "support": { "issues": "https://github.com/symplify/vendor-patches/issues", - "source": "https://github.com/symplify/vendor-patches/tree/11.3.7" + "source": "https://github.com/symplify/vendor-patches/tree/11.4.1" }, "funding": [ { @@ -5979,7 +5967,7 @@ "type": "github" } ], - "time": "2024-01-23T17:12:30+00:00" + "time": "2025-02-18T08:19:39+00:00" }, { "name": "tijsverkoyen/css-to-inline-styles", @@ -6256,36 +6244,36 @@ "packages-dev": [ { "name": "barryvdh/laravel-ide-helper", - "version": "v3.5.4", + "version": "v3.5.5", "source": { "type": "git", "url": "https://github.com/barryvdh/laravel-ide-helper.git", - "reference": "980a87e250fc2a7558bc46e07f61c7594500ea53" + "reference": "8d441ec99f8612b942b55f5183151d91591b618a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/barryvdh/laravel-ide-helper/zipball/980a87e250fc2a7558bc46e07f61c7594500ea53", - "reference": "980a87e250fc2a7558bc46e07f61c7594500ea53", + "url": "https://api.github.com/repos/barryvdh/laravel-ide-helper/zipball/8d441ec99f8612b942b55f5183151d91591b618a", + "reference": "8d441ec99f8612b942b55f5183151d91591b618a", "shasum": "" }, "require": { "barryvdh/reflection-docblock": "^2.3", "composer/class-map-generator": "^1.0", "ext-json": "*", - "illuminate/console": "^11.15", - "illuminate/database": "^11.15", - "illuminate/filesystem": "^11.15", - "illuminate/support": "^11.15", + "illuminate/console": "^11.15 || ^12", + "illuminate/database": "^11.15 || ^12", + "illuminate/filesystem": "^11.15 || ^12", + "illuminate/support": "^11.15 || ^12", "php": "^8.2" }, "require-dev": { "ext-pdo_sqlite": "*", "friendsofphp/php-cs-fixer": "^3", - "illuminate/config": "^11.15", - "illuminate/view": "^11.15", + "illuminate/config": "^11.15 || ^12", + "illuminate/view": "^11.15 || ^12", "mockery/mockery": "^1.4", - "orchestra/testbench": "^9.2", - "phpunit/phpunit": "^10.5", + "orchestra/testbench": "^9.2 || ^10", + "phpunit/phpunit": "^10.5 || ^11.5.3", "spatie/phpunit-snapshot-assertions": "^4 || ^5", "vimeo/psalm": "^5.4", "vlucas/phpdotenv": "^5" @@ -6334,7 +6322,7 @@ ], "support": { "issues": "https://github.com/barryvdh/laravel-ide-helper/issues", - "source": "https://github.com/barryvdh/laravel-ide-helper/tree/v3.5.4" + "source": "https://github.com/barryvdh/laravel-ide-helper/tree/v3.5.5" }, "funding": [ { @@ -6346,7 +6334,7 @@ "type": "github" } ], - "time": "2025-01-14T09:07:00+00:00" + "time": "2025-02-11T13:59:46+00:00" }, { "name": "barryvdh/reflection-docblock", @@ -6402,16 +6390,16 @@ }, { "name": "composer/class-map-generator", - "version": "1.5.0", + "version": "1.6.0", "source": { "type": "git", "url": "https://github.com/composer/class-map-generator.git", - "reference": "4b0a223cf5be7c9ee7e0ef1bc7db42b4a97c9915" + "reference": "ffe442c5974c44a9343e37a0abcb1cc37319f5b9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/class-map-generator/zipball/4b0a223cf5be7c9ee7e0ef1bc7db42b4a97c9915", - "reference": "4b0a223cf5be7c9ee7e0ef1bc7db42b4a97c9915", + "url": "https://api.github.com/repos/composer/class-map-generator/zipball/ffe442c5974c44a9343e37a0abcb1cc37319f5b9", + "reference": "ffe442c5974c44a9343e37a0abcb1cc37319f5b9", "shasum": "" }, "require": { @@ -6455,7 +6443,7 @@ ], "support": { "issues": "https://github.com/composer/class-map-generator/issues", - "source": "https://github.com/composer/class-map-generator/tree/1.5.0" + "source": "https://github.com/composer/class-map-generator/tree/1.6.0" }, "funding": [ { @@ -6471,7 +6459,7 @@ "type": "tidelift" } ], - "time": "2024-11-25T16:11:06+00:00" + "time": "2025-02-05T10:05:34+00:00" }, { "name": "composer/pcre", @@ -6589,16 +6577,16 @@ }, { "name": "myclabs/deep-copy", - "version": "1.12.1", + "version": "1.13.0", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "123267b2c49fbf30d78a7b2d333f6be754b94845" + "reference": "024473a478be9df5fdaca2c793f2232fe788e414" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/123267b2c49fbf30d78a7b2d333f6be754b94845", - "reference": "123267b2c49fbf30d78a7b2d333f6be754b94845", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/024473a478be9df5fdaca2c793f2232fe788e414", + "reference": "024473a478be9df5fdaca2c793f2232fe788e414", "shasum": "" }, "require": { @@ -6637,7 +6625,7 @@ ], "support": { "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.12.1" + "source": "https://github.com/myclabs/DeepCopy/tree/1.13.0" }, "funding": [ { @@ -6645,7 +6633,7 @@ "type": "tidelift" } ], - "time": "2024-11-08T17:47:46+00:00" + "time": "2025-02-12T12:17:51+00:00" }, { "name": "nette/robot-loader", @@ -6833,16 +6821,16 @@ }, { "name": "phpecs/phpecs", - "version": "2.0.0", + "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/TomasVotruba/ecs.git", - "reference": "da6b0acc5555c80942edb7a286d4e2e9ab3f1325" + "reference": "048894c4d4bddee273ff5372acd0a4e692849874" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/TomasVotruba/ecs/zipball/da6b0acc5555c80942edb7a286d4e2e9ab3f1325", - "reference": "da6b0acc5555c80942edb7a286d4e2e9ab3f1325", + "url": "https://api.github.com/repos/TomasVotruba/ecs/zipball/048894c4d4bddee273ff5372acd0a4e692849874", + "reference": "048894c4d4bddee273ff5372acd0a4e692849874", "shasum": "" }, "require": { @@ -6851,12 +6839,15 @@ }, "type": "library", "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], "description": "The easiest way to use Coding Standard", "support": { "issues": "https://github.com/TomasVotruba/ecs/issues", - "source": "https://github.com/TomasVotruba/ecs/tree/2.0.0" + "source": "https://github.com/TomasVotruba/ecs/tree/2.0.1" }, - "time": "2025-01-17T09:46:12+00:00" + "time": "2025-02-18T08:38:45+00:00" }, { "name": "phpstan/extension-installer", @@ -6959,23 +6950,23 @@ }, { "name": "phpunit/php-code-coverage", - "version": "11.0.8", + "version": "11.0.9", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "418c59fd080954f8c4aa5631d9502ecda2387118" + "reference": "14d63fbcca18457e49c6f8bebaa91a87e8e188d7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/418c59fd080954f8c4aa5631d9502ecda2387118", - "reference": "418c59fd080954f8c4aa5631d9502ecda2387118", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/14d63fbcca18457e49c6f8bebaa91a87e8e188d7", + "reference": "14d63fbcca18457e49c6f8bebaa91a87e8e188d7", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^5.3.1", + "nikic/php-parser": "^5.4.0", "php": ">=8.2", "phpunit/php-file-iterator": "^5.1.0", "phpunit/php-text-template": "^4.0.1", @@ -6987,7 +6978,7 @@ "theseer/tokenizer": "^1.2.3" }, "require-dev": { - "phpunit/phpunit": "^11.5.0" + "phpunit/phpunit": "^11.5.2" }, "suggest": { "ext-pcov": "PHP extension that provides line coverage", @@ -7025,7 +7016,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/11.0.8" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/11.0.9" }, "funding": [ { @@ -7033,7 +7024,7 @@ "type": "github" } ], - "time": "2024-12-11T12:34:27+00:00" + "time": "2025-02-25T13:26:39+00:00" }, { "name": "phpunit/php-file-iterator", @@ -8350,16 +8341,16 @@ }, { "name": "symplify/easy-coding-standard", - "version": "12.5.5", + "version": "12.5.8", "source": { "type": "git", "url": "https://github.com/easy-coding-standard/easy-coding-standard.git", - "reference": "16a6ac7f452e230fdcc81f1b35b2366903fcecf3" + "reference": "2bf0e468dc9679f3835c835cd3fd4a25ff6e4e14" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/easy-coding-standard/easy-coding-standard/zipball/16a6ac7f452e230fdcc81f1b35b2366903fcecf3", - "reference": "16a6ac7f452e230fdcc81f1b35b2366903fcecf3", + "url": "https://api.github.com/repos/easy-coding-standard/easy-coding-standard/zipball/2bf0e468dc9679f3835c835cd3fd4a25ff6e4e14", + "reference": "2bf0e468dc9679f3835c835cd3fd4a25ff6e4e14", "shasum": "" }, "require": { @@ -8395,7 +8386,7 @@ ], "support": { "issues": "https://github.com/easy-coding-standard/easy-coding-standard/issues", - "source": "https://github.com/easy-coding-standard/easy-coding-standard/tree/12.5.5" + "source": "https://github.com/easy-coding-standard/easy-coding-standard/tree/12.5.8" }, "funding": [ { @@ -8407,7 +8398,7 @@ "type": "github" } ], - "time": "2025-01-02T08:43:03+00:00" + "time": "2025-01-31T13:59:38+00:00" }, { "name": "theseer/tokenizer", diff --git a/resources/blog/posts/2025/2025-03-03-how-to-strangle-your-project-with-strangle-anti-pattern.md b/resources/blog/posts/2025/2025-03-03-how-to-strangle-your-project-with-strangle-anti-pattern.md new file mode 100644 index 000000000..bd5fc264b --- /dev/null +++ b/resources/blog/posts/2025/2025-03-03-how-to-strangle-your-project-with-strangle-anti-pattern.md @@ -0,0 +1,109 @@ +--- +id: 78 +title: "How to Strangle your Project with Strangle Anti-Pattern" +perex: | + Nearly half of the project we help upgrade have tried the upgrade before on their own. + They've introduced infamous "strangle pattern". It's a way to upgrade project separating one part of the codebase from the rest at a time. + + Those companies reach us, because while the strangle pattern is great in theory, it actually strangles the project in practice. They're unable to move, they use now 2 frameworks instead of one and team has to work with complexity squared. + + Today we'd like to share why it's a terrible choice and what upgrade strategy to take instead. +--- + + +## What is "Strangle Pattern"? + +In programming, the strangler pattern is an architectural pattern that involves wrapping old code, with the intent of redirecting it to newer code or to log uses of the old code ([taken from Wikipedia](https://en.wikipedia.org/wiki/Strangler_fig_pattern)). + +How does it look in practise? + +Let's say we have an old CakePHP, CodeIgniter, Yii or plain PHP project and you want to upgrade to Symfony or Laravel. You start by isolating part of the project, e.g. invoicing, and wrap it with Symfony or Laravel controller. + +It practise, it can look something like: + +
+ +
+ + From Monolith to Microservices + +
+ +That way, we'll have soon the full invoicing in Symfony or Laravel, right? + +
+ +No, in practise **this is a terrible idea**. Why? + +## Just a single Controller + +What is necessary to make to introduce a single Symfony/Laravel controller into an old project? + +* we have to setup HTTP layer for response and request +* we have to setup routing +* we have to setup dependency injection container and interconnect it with old project +* we have to make sure the services used in controller are correctly autowired + +To setup single invoicing controller, we have to setup the whole Symfony/Laravel HTTP, DI and Routing layers. This could be months of work without showing any value to the customer. + +
+ +## The Mythical Man-Month + +Have you heard of [The Mythical Man-Month](https://en.wikipedia.org/wiki/The_Mythical_Man-Month) book? Its central theme is that **adding manpower to a software project that is behind schedule delays it even longer**. + +
+Same way adding parallel framework
+will make upgrading the project even harder. +
+ +If we could come to a project in a moment before they put 1 year into a strangle pattern upgrade, we could save them a lot of time and money. It usually takes 3-6 months just to untangle the project to original state. + +
+ +Let's say we finished the upgrade of invoicing to Symfony/Laravel framework. Now we've done almost full framework migration path, but there are still 3 modules we have to upgrade. We have just quadrupled our budget. In our experience, here is around 15-30 modules in such PHP projects. + +What is the result? We now have a legacy project with 2 frameworks instead of 1. To upgrade a PHP version, we have to now upgrade 2 frameworks, not just 1. To add a new layer, e.g. routing security, we have find a way how both frameworks can work together. + +## Pattern Refactoring + +Instead of chopping of project and doubling everything, we should focus on smallest steps possible to make [project upgrade a success](/blog/7-traits-of-successful-upgrade-companies). We use [pattern refactoring](https://tomasvotruba.com/blog/2019/04/15/pattern-refactoring) approach. + +How does pattern refactoring look like? The gist of this approach is to refactor **single pattern in the whole project at a time**. +That means we always have one framework responsible for one part. There are never 2 frameworks handling the same area e.g. controllers, like in strangle pattern. + +### Step by step + +1. Find a pattern that is used in the whole project, e.g. configuration, routing or dependency injection container +2. Create fully automated strategy using Rector and symfony/finder + php-parser +3. Have a way to quickly verify if the migration works or not, e.g. using [smoke testing](https://tomasvotruba.com/blog/cost-effective-container-smoke-tests-every-symfony-project-must-have) +4. Would it take more than 2 weeks? Find a simpler pattern + +That way we have always one framework responsible for one part of the project. + +## Benefits of Pattern Refactoring + +* the project is always in a working state +* the project is always improving - even if we decide to pause the upgrade process in 4 months, we'll have a better project than we started with +* the work is always finished - there are no stale pull-requests that take a month to review +* the pull-request as small, independent on each other and easy to review +* great use of CLI automation - 80 % of patterns are repeating in the most of projects + +
+ +We use this approach since one of our first upgrades in 2017. We only improve the CLI tooling and automation around it. If we discover a new pattern, we add it to Rector/tools and use it instantly in the next project. + +
+ +### Case Study + +This way, you can migrate whole project to a Laravel under a year - [see this Rector case study](/blog/success-story-of-automated-framework-migration-from-fuelphp-to-laravel-of-400k-lines-application). + + +
+ +The pattern refactoring is not just for very complex legacy-framework to Symfony/Laravel migrations. They're also suitable for long framework upgrades like [Symfony 2.8 to 7.2](https://tomasvotruba.com/blog/off-the-beaten-path-to-upgrade-symfony-28-to-72). Once you learn it, you can re-use and benefit from it in many projects. + +
+ +Happy coding! diff --git a/resources/views/blog/blog.blade.php b/resources/views/blog/blog.blade.php index 7c243180a..f7ee7a684 100644 --- a/resources/views/blog/blog.blade.php +++ b/resources/views/blog/blog.blade.php @@ -2,13 +2,13 @@ @section('main')
-

{{ $page_title }}

+

{{ $page_title }}

@php /** @var \App\Entity\Post[] $posts */ @endphp @foreach ($posts as $post) -
-

+
+

@@ -16,13 +16,11 @@

-
+
- -
@endforeach
diff --git a/resources/views/blog/post.blade.php b/resources/views/blog/post.blade.php index 8a6e0c59b..42f2dadd8 100644 --- a/resources/views/blog/post.blade.php +++ b/resources/views/blog/post.blade.php @@ -50,7 +50,9 @@

-

{{ $post->getTitle() }}

+

+ {{ $post->getTitle() }} +

@if ($post->getSinceRector())
diff --git a/resources/views/homepage/contact.blade.php b/resources/views/homepage/contact.blade.php index 7e3217349..b0cdad3de 100644 --- a/resources/views/homepage/contact.blade.php +++ b/resources/views/homepage/contact.blade.php @@ -79,8 +79,8 @@

Edukai, s.r.o.

- Dubova 4
- 460 01, Liberec + Jagellonska 2427/19
+ Prague, 130 00
Czech Republic

diff --git a/src/Controller/Blog/BlogController.php b/src/Controller/Blog/BlogController.php index af6621ba1..48fe1e59d 100644 --- a/src/Controller/Blog/BlogController.php +++ b/src/Controller/Blog/BlogController.php @@ -18,7 +18,7 @@ public function __construct( public function __invoke(): View { return \view('blog/blog', [ - 'page_title' => 'Read about Rector', + 'page_title' => 'Learn about Rector, Upgrades and Planning', 'posts' => $this->postRepository->getPosts(), ]); } From 876b3c782e78cfb51294357b1ed1e94581456493 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Mon, 3 Mar 2025 12:54:51 +0100 Subject: [PATCH 2/2] gram --- ...your-project-with-strangle-anti-pattern.md | 60 ++++++++++--------- src/Ast/Request/AstFormRequest.php | 6 +- 2 files changed, 36 insertions(+), 30 deletions(-) diff --git a/resources/blog/posts/2025/2025-03-03-how-to-strangle-your-project-with-strangle-anti-pattern.md b/resources/blog/posts/2025/2025-03-03-how-to-strangle-your-project-with-strangle-anti-pattern.md index bd5fc264b..d06eede8f 100644 --- a/resources/blog/posts/2025/2025-03-03-how-to-strangle-your-project-with-strangle-anti-pattern.md +++ b/resources/blog/posts/2025/2025-03-03-how-to-strangle-your-project-with-strangle-anti-pattern.md @@ -2,10 +2,10 @@ id: 78 title: "How to Strangle your Project with Strangle Anti-Pattern" perex: | - Nearly half of the project we help upgrade have tried the upgrade before on their own. - They've introduced infamous "strangle pattern". It's a way to upgrade project separating one part of the codebase from the rest at a time. + Nearly half of the projects we help upgrade have tried the upgrade before on their own. + They've introduced the infamous "strangle pattern". It's a way to upgrade a project separating one part of the codebase from the rest at a time. - Those companies reach us, because while the strangle pattern is great in theory, it actually strangles the project in practice. They're unable to move, they use now 2 frameworks instead of one and team has to work with complexity squared. + Those companies reach us because while the strangle pattern is great in theory, it rather strangles the project in practice. They're unable to move, they use now 2 frameworks instead of one and the team has to work with complexity squared. Today we'd like to share why it's a terrible choice and what upgrade strategy to take instead. --- @@ -15,11 +15,11 @@ perex: | In programming, the strangler pattern is an architectural pattern that involves wrapping old code, with the intent of redirecting it to newer code or to log uses of the old code ([taken from Wikipedia](https://en.wikipedia.org/wiki/Strangler_fig_pattern)). -How does it look in practise? +How does it look in practice? -Let's say we have an old CakePHP, CodeIgniter, Yii or plain PHP project and you want to upgrade to Symfony or Laravel. You start by isolating part of the project, e.g. invoicing, and wrap it with Symfony or Laravel controller. +Let's say we have an old CakePHP, CodeIgniter, Yii, or plain PHP project and you want to upgrade to Symfony or Laravel. You start by isolating part of the project, e.g. invoicing, and wrap it with Symfony or Laravel controller. -It practise, it can look something like: +In practice, it can look something like:
@@ -33,18 +33,18 @@ That way, we'll have soon the full invoicing in Symfony or Laravel, right?
-No, in practise **this is a terrible idea**. Why? +No, in practice **this is a terrible idea**. Why? ## Just a single Controller -What is necessary to make to introduce a single Symfony/Laravel controller into an old project? +What is necessary to introduce a single Symfony/Laravel controller into an old project? -* we have to setup HTTP layer for response and request -* we have to setup routing -* we have to setup dependency injection container and interconnect it with old project -* we have to make sure the services used in controller are correctly autowired +* we have to add an HTTP layer for response and request +* we have to set up the routing +* we have to set up the dependency injection container and interconnect it with an old project +* we have to make sure the services used in the controller are correctly autowired -To setup single invoicing controller, we have to setup the whole Symfony/Laravel HTTP, DI and Routing layers. This could be months of work without showing any value to the customer. +To set up a single invoicing controller, we have to set up the whole Symfony/Laravel HTTP, DI, and Routing layers. This could be months of work without showing any value to the customer.
@@ -53,29 +53,35 @@ To setup single invoicing controller, we have to setup the whole Symfony/Laravel Have you heard of [The Mythical Man-Month](https://en.wikipedia.org/wiki/The_Mythical_Man-Month) book? Its central theme is that **adding manpower to a software project that is behind schedule delays it even longer**.
-Same way adding parallel framework
+Same way as adding a parallel framework
will make upgrading the project even harder.
-If we could come to a project in a moment before they put 1 year into a strangle pattern upgrade, we could save them a lot of time and money. It usually takes 3-6 months just to untangle the project to original state. +If we could come to a project in a moment before they put 1 year into a strangle pattern upgrade, we could save them a lot of time and money. It usually takes 3-6 months just to untangle the project to its original state.
-Let's say we finished the upgrade of invoicing to Symfony/Laravel framework. Now we've done almost full framework migration path, but there are still 3 modules we have to upgrade. We have just quadrupled our budget. In our experience, here is around 15-30 modules in such PHP projects. +Let's say we finished the upgrade of invoicing module to the Symfony/Laravel framework. **Now we've done almost the full framework migration path, but there are still 3 modules we have to upgrade. We have just quadrupled the upgrade costs**. In our experience, there are around 15-30 modules in such PHP projects. -What is the result? We now have a legacy project with 2 frameworks instead of 1. To upgrade a PHP version, we have to now upgrade 2 frameworks, not just 1. To add a new layer, e.g. routing security, we have find a way how both frameworks can work together. +What is the result? + +* We now have a legacy project with 2 frameworks instead of 1. +* To upgrade a PHP version, we have to now upgrade 2 frameworks, not just 1. +* To add a new layer, e.g. routing security, we have found a way how both frameworks can work together. ## Pattern Refactoring -Instead of chopping of project and doubling everything, we should focus on smallest steps possible to make [project upgrade a success](/blog/7-traits-of-successful-upgrade-companies). We use [pattern refactoring](https://tomasvotruba.com/blog/2019/04/15/pattern-refactoring) approach. +Instead of chopping off the project and doubling everything, we should focus on the smallest steps possible to make [project upgrade a success](/blog/7-traits-of-successful-upgrade-companies). We use the [pattern refactoring](https://tomasvotruba.com/blog/2019/04/15/pattern-refactoring) approach. + +What does pattern refactoring look like? The gist of this approach is to refactor **single pattern in the whole project at a time**. +That means we always have one framework responsible for one part. There are never 2 frameworks handling the same area e.g. controllers, like in the strangle pattern. -How does pattern refactoring look like? The gist of this approach is to refactor **single pattern in the whole project at a time**. -That means we always have one framework responsible for one part. There are never 2 frameworks handling the same area e.g. controllers, like in strangle pattern. +
### Step by step -1. Find a pattern that is used in the whole project, e.g. configuration, routing or dependency injection container -2. Create fully automated strategy using Rector and symfony/finder + php-parser +1. Find a pattern that is used in the whole project, e.g. configuration, routing, or dependency injection container +2. Create a fully automated strategy using Rector and symfony/finder + php-parser 3. Have a way to quickly verify if the migration works or not, e.g. using [smoke testing](https://tomasvotruba.com/blog/cost-effective-container-smoke-tests-every-symfony-project-must-have) 4. Would it take more than 2 weeks? Find a simpler pattern @@ -85,19 +91,19 @@ That way we have always one framework responsible for one part of the project. * the project is always in a working state * the project is always improving - even if we decide to pause the upgrade process in 4 months, we'll have a better project than we started with -* the work is always finished - there are no stale pull-requests that take a month to review -* the pull-request as small, independent on each other and easy to review -* great use of CLI automation - 80 % of patterns are repeating in the most of projects +* the work is always finished - there are no stale pull requests that take a month to review +* the pull-request as small, independent of each other, and easy to review +* great use of CLI automation - 80 % of patterns are repeating in most of projects
-We use this approach since one of our first upgrades in 2017. We only improve the CLI tooling and automation around it. If we discover a new pattern, we add it to Rector/tools and use it instantly in the next project. +We have been using this approach since one of our first upgrades in 2017. We only improve the CLI tooling and automation around it. If we discover a new pattern, we add it to the Rector/tools and use it instantly in the next project.
### Case Study -This way, you can migrate whole project to a Laravel under a year - [see this Rector case study](/blog/success-story-of-automated-framework-migration-from-fuelphp-to-laravel-of-400k-lines-application). +This way, you can migrate the whole project to Laravel in under a year - [see this Rector case study](/blog/success-story-of-automated-framework-migration-from-fuelphp-to-laravel-of-400k-lines-application).
diff --git a/src/Ast/Request/AstFormRequest.php b/src/Ast/Request/AstFormRequest.php index b359d2e4f..16b8e146e 100644 --- a/src/Ast/Request/AstFormRequest.php +++ b/src/Ast/Request/AstFormRequest.php @@ -29,12 +29,12 @@ public function rules(): array $shortPhpContentsRule = app() ->make(ShortPhpContentsRule::class); - /** @var ValidAndSafePhpSyntaxRule $validPhpSyntaxRule */ - $validPhpSyntaxRule = app() + /** @var ValidAndSafePhpSyntaxRule $validAndSafePhpSyntaxRule */ + $validAndSafePhpSyntaxRule = app() ->make(ValidAndSafePhpSyntaxRule::class); return [ - self::KEY_PHP_CONTENTS => ['required', 'string', $shortPhpContentsRule, $validPhpSyntaxRule], + self::KEY_PHP_CONTENTS => ['required', 'string', $shortPhpContentsRule, $validAndSafePhpSyntaxRule], ]; }