<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Benoit Condaminet on Medium]]></title>
        <description><![CDATA[Stories by Benoit Condaminet on Medium]]></description>
        <link>https://medium.com/@benoit-condaminet?source=rss-d395db49123------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*8bc7hDoNobVRaDv5jpCq6w.jpeg</url>
            <title>Stories by Benoit Condaminet on Medium</title>
            <link>https://medium.com/@benoit-condaminet?source=rss-d395db49123------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Fri, 08 May 2026 13:11:19 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@benoit-condaminet/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Ignore custom indexes on doctrine dbal]]></title>
            <link>https://medium.com/yousign-engineering-product/ignore-custom-indexes-on-doctrine-dbal-b5131dd22071?source=rss-d395db49123------2</link>
            <guid isPermaLink="false">https://medium.com/p/b5131dd22071</guid>
            <dc:creator><![CDATA[Benoit Condaminet]]></dc:creator>
            <pubDate>Mon, 28 Aug 2023 08:11:02 GMT</pubDate>
            <atom:updated>2023-08-28T08:11:02.585Z</atom:updated>
            <content:encoded><![CDATA[<h3>Ignore custom indexes on Doctrine ORM</h3><p>Sometimes, we need to create complex indexes on a database, like creating a GIN index using trgm extension for Postgres, etc. Currently, we can’t generate this kind of index definition using doctrine index mapping configuration.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Z0whiByIVWFsHsw_RC3xbg.jpeg" /><figcaption>Picture credit : <a href="https://unsplash.com/fr/@francogio?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Franco Antonio Giovanella</a></figcaption></figure><p>For this purpose, the best way to <strong>create such indexes is to add them manually inside a doctrine migration</strong>. But by doing this, the table mapping is no more synchronized with the database, so command like this one (using Symfony console):</p><pre>bin/console doctrine:schema:validate</pre><p>Will fail, and creating new migrations will be bloated with the DROP INDEX SQL statement.</p><p>To make it properly work again with doctrine, a pertinent solution will be to ignore such indexes from doctrine dbal schema parser.</p><h4>How to</h4><p>I’m using these packages versions which are the most recent when I wrote this article :</p><ul><li>doctrine/dbal: 3.6.5</li><li>The Symfony doctrine/doctrine-bundle: 2.10.2</li></ul><p>On latest doctrine dbal versions, <a href="https://github.com/doctrine/dbal/issues/5784">listening to schema related events is deprecated</a>, and will be removed in doctrine dbal v4.</p><p>The proper way is to override the <strong>SQLSchemaManager</strong>. Depending on your Database, you need to extend the good one. On my side, using Postgres, have to create a class that extend : <em>Doctrine\DBAL\Schema\PostgreSQLSchemaManager</em></p><p>Example (don’t forget to add your namespace / rename if needed) :</p><pre>&lt;?php<br><br>class CustomPostgreSQLSchemaManager extends \Doctrine\DBAL\Schema\PostgreSQLSchemaManager<br>{<br>    private const INDEXES_TO_FILTER = [<br>        &#39;idx_custom1&#39;,<br>        &#39;idx_custom2&#39;,<br>    ];<br><br>    protected function _getPortableTableIndexesList($tableIndexes, $tableName = null)<br>    {<br>        $indexes = parent::_getPortableTableIndexesList($tableIndexes, $tableName);<br><br>        foreach (self::INDEXES_TO_FILTER as $index) {<br>            if (isset($indexes[$index])) {<br>                unset($indexes[$index]);<br>            }<br>        }<br><br>        return $indexes;<br>    }<br>}</pre><p>Here, indexes named “idx_custom1” and “idx_custom2” will be ignored. To configure ignored indexes we just need to update the <strong>INDEXES_TO_FILTER</strong> const array.</p><p>Now that we set up the index ignore/filter system, we still need to tell doctrine to use our <strong>CustomPostgreSQLSchemaManager</strong>. Looking at <a href="https://www.doctrine-project.org/projects/doctrine-dbal/en/current/reference/schema-manager.html#overriding-the-schema-manager">doctrine dbal documentation</a>, it tells us that we need to set a custom <strong>SchemaManagerFactory</strong>.</p><p>You can follow the doctrine documentation, but if you are using the Symfony doctrine-bundle, you can do that from the <strong>config/doctrine.yaml</strong> file.</p><p>Simply add the “schema_manager_factory” config key in your connection configuration with your own factory service, or if you already override the doctrine platform service with your own, we just need to override a method and don’t need a custom <strong>SchemaManagerFactory</strong>. We can simply use the doctrine <strong>DefaultSchemaManagerFactory</strong> instead of creating our own.</p><p>Note : if you don’t configure the SchemaManagerFactory, with Symfony doctrine-bundle, the SchemaManagerFactory used is the <strong>LegacySchemaManagerFactory. </strong>This one get the SchemaManager through the doctrine driver, it’s deprecated and will be removed in doctrine/dbal v4. So better use the <strong>DefaultSchemaManagerFactory</strong> right now <strong>👍</strong></p><p>If we go back to our <strong>config/doctrine.yaml:</strong></p><pre>platform_service: Namespace\To\My\CustomPostgreSQLPlatformService<br>schema_manager_factory: &#39;doctrine.dbal.default_schema_manager_factory&#39;</pre><p>Here we use a custom platform service, and use the doctrine default SchemaManagerFactory. Now we just need to add this method in our <strong>CustomPostgreSQLPlatformService</strong>:</p><pre>class CustomPostgreSQLPlatformService extends \Doctrine\DBAL\Platforms\PostgreSQLPlatform<br>{<br><br>    public function createSchemaManager(Connection $connection): CustomPostgreSQLSchemaManager<br>    {<br>        return new CustomPostgreSQLSchemaManager($connection, $this);<br>    }<br><br>}</pre><p>Again, extend the platform matching your database type (PostgreSQLPlatform here).</p><p>If you want to know how it works, I let you look at the <em>Doctrine\DBAL\Schema\DefaultSchemaManagerFactory</em> class.</p><p>Spoiler : it calls the overridden method above from our platform service👆</p><p>And that’s it, generating new migrations no longer delete custom indexes.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b5131dd22071" width="1" height="1" alt=""><hr><p><a href="https://medium.com/yousign-engineering-product/ignore-custom-indexes-on-doctrine-dbal-b5131dd22071">Ignore custom indexes on doctrine dbal</a> was originally published in <a href="https://medium.com/yousign-engineering-product">Yousign Engineering &amp; Product</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Deal with major upgrades in PHP]]></title>
            <link>https://medium.com/yousign-engineering-product/deal-with-major-upgrades-in-php-490ed55c54a1?source=rss-d395db49123------2</link>
            <guid isPermaLink="false">https://medium.com/p/490ed55c54a1</guid>
            <category><![CDATA[php]]></category>
            <category><![CDATA[releases]]></category>
            <category><![CDATA[laravel]]></category>
            <category><![CDATA[doctrine]]></category>
            <category><![CDATA[symfony]]></category>
            <dc:creator><![CDATA[Benoit Condaminet]]></dc:creator>
            <pubDate>Thu, 13 Apr 2023 15:00:54 GMT</pubDate>
            <atom:updated>2023-04-13T15:00:54.471Z</atom:updated>
            <content:encoded><![CDATA[<p>Manage major upgrades in PHP can be a big deal for companies.</p><p>We all have this fear, to break our production because of these upgrades. A lot of companies postpone them because of this, until they face the inevitable.</p><p>Waiting and running a deprecated version of PHP (or any other dependencies of your code) is way worse. It can lead to vulnerability exploit, and can severely damage your whole business.</p><p>It’s a mandatory step that cannot be neglected. And the longer you wait, the harder it will be to upgrade.</p><p>At Yousign, we often face this situation and we wanted to share with you how we deal with major upgrade in PHP 🐘</p><figure><img alt="picture of a robot with multiple arms" src="https://cdn-images-1.medium.com/max/1024/1*CW94ebJVnj3JRUIgRQNnzQ@2x.png" /></figure><h3>▶️ Define your upgrade plan</h3><p>Before starting our upgrade migration, we have to prepare some stuff. Let’s define the steps required for this upgrade to succeed. It depends on how your product works, but in our case we identify some steps, that can be transposed to almost any major dependency upgrade.</p><h3>📑 Read the upgrading guide</h3><p>The first thing to do is to read the official upgrading guide.</p><p>For Symfony major version upgrade: <a href="https://symfony.com/doc/current/setup/upgrade_major.html">https://symfony.com/doc/current/setup/upgrade_major.html</a></p><p>If your major upgrade concerns a composer dependency, you can take a look to the matching Github repository, most of them have a <strong>UPGRADE.md</strong> in the repository root path.</p><blockquote>Take a look at <a href="https://github.com/doctrine/orm/blob/2.14.x/UPGRADE.md">the doctrine UPGRADE.md</a></blockquote><h3>🪝 Release blockers</h3><p>We begin the journey of a major version upgrade by identifying blockers, for PHP update we can rely on composer to tell us which dependencies are blocking the targeted update :</p><pre># If we want to update PHP to 8.1<br>composer why-not php 8.1<br># If we want to update symfony to 6.2<br>composer why-not symfony/framework-bundle 6.2</pre><p>It’s a first step to identify packages that need to be updated.</p><p>Occasionally, a blocking package needs to be updated to a new major version, you can apply this guide again, release blockers of your blockers 😅 and roll out the guide.</p><h4>📩 Update blocking package(s)</h4><p>Fix each blocking package one by one in a dedicated merge/pull request.</p><p>Update if needed the versioning constraint for the package in the composer.json file to be certain you can reach the wanted version (latest is better)</p><p>Update the package by doing a :</p><pre>composer update the-blocking/package --with-dependencies</pre><p>You can “force” a specific version of a package, if you want to downgrade it, or freeze its version.</p><p>You can do it by using the “with” parameter, for example if you intend to fix friendsofphp/php-cs-fixer to 3.13.0 and don’t want the last update (that change too many things in the codebase) :</p><pre>composer update some/package --with friendsofphp/php-cs-fixer:3.13.0</pre><p>Note that it should be a temporary workaround, as any future composer update will update the fixed package version.</p><h4>🩹 Fix deprecation</h4><p>Find a way to log and fix all deprecation issues related to the part you want to update (PHP, Symfony, Doctrine or anything else) before doing the major upgrade.</p><p>Deprecation issues can be printed by launching PHPUnit test, or through the logs. You can see them too in the Symfony profiler page 👍</p><p>It’s really important here to have a good test coverage, to catch as many deprecation issues as possible when launching your PHPUnit tests.</p><h4>🎳 Update all composer dependencies</h4><p>It can be a tricky part, but if your composer.json versioning constraints are good, it can be good to do a last composer update in a dedicated merge/pull request :</p><pre>composer update</pre><h3>🔄 Iteration step</h3><p>Once you think you have released all blockers, you can do the major update. It consists of trying to do the update, and roll out a checklist until everything is ✅.</p><p>The changes have to stay on its branch (don’t merge it to main branch, read until the end 🙏)</p><p>Each time you have an issue, it’s better to fix it in another dedicated merge request, before doing the main update (if possible).</p><p>Once new blockers are fixed, rebase and repeat until everything is green! The goal is to not have a long living branch with a lot of change, which is a pain to maintain (conflicts with main branch, etc).</p><blockquote>The more you can fix and merge before doing the major upgrade, the better it is!</blockquote><figure><img alt="a graphic reprensenting the iteration step cycle" src="https://cdn-images-1.medium.com/max/1024/1*-XKhVxKA26SIm5I6UcFvEw.png" /></figure><h4>🛠️ PHP major update</h4><p>It consists of updating local env installation, and Docker image if you have one. You need to update the PHP version used in composer.json too. Once done, a composer update should be needed to update packages according to this new PHP version.</p><h4>🛠️ Dependency major update</h4><p>Update the wanted dependency related packages.</p><p>With symfony, update allsymfony/* packages version constraint to the desired version in the composer.json</p><p>You can try to update them with a composer update, then use —dry-run to simulate the update and see if it’s okay or if you have other blocking package(s) (that you should update in a dedicated merge/pull request <strong>before</strong> doing the main update)</p><h4>☑️ Checklist example</h4><p>The checklist really depends on your workflow, tooling, CI/CD, etc. In our case:</p><ul><li>Symfony cache clear run without issues (or Laravel or whatever)</li><li>PHP code style and static analyzers run without issues (PHP-CS-Fixer / PHPStan / Rector / etc)</li><li>Your PHPUnit Testing suite run and is green</li><li>Your existing merge / pull request CI/CD have to be ✅</li></ul><p>Check that your observability integration(s) still works well (you can still read logs and metrics).</p><p>Test that monolog is still doing his job if you use it, or that your log aggregator properly retrieves your PHP logs in the updated Docker Image, etc.</p><h3>🏁 Challenge the update</h3><p>Once the checklist is okay, you can test the update to look for any performance regressions. It can be achieved by launching a dedicated Performance Benchmark.</p><p>Actually, the best is to reuse any existing, previously made performance test to have something to compare with.</p><p>Another thing to take care of when you often deploy, is <strong>zero downtime deployment</strong> compliance. A major update can lead to zero downtime issues, for example if you rely on object serialized in a message broker like RabbitMQ. For further information, I let you read <a href="https://smaine-milianni.medium.com/the-b768b8fe315c">this excellent article</a>.</p><h3>🚀 Release process</h3><p>Because it’s a major update, we need to take precautions. So, deployment in production needs some additional care.</p><p>The major upgrade should be done in a dedicated release, and should include only the major upgrade commit (nothing else!). It’s of course not mandatory if you feel confident enough, but highly recommended.</p><h4>🗨️ Communication</h4><p>Communication is crucial here, so once everything is green, have a meeting with stakeholders to agree about a release date. This date should be communicated some days before.</p><h4>🥵 The release day</h4><p>First, it’s best to do a dedicated release for your change. Because you upgrade a major version constraint, it’s best to not ship other stuff in same time so in case of issues, you are sure it’s related to what you did, and not another commit.</p><p>Then, isolated this release allow you to rollback more easily.</p><p>My advice is to start your normal daily release process before. And wait, that all deployments are ended, and that any post deployment tests / tasks are finished.</p><ul><li><strong>Prepare a dedicated release</strong> from the just deployed version. It depend on your CD workflow, but you can rely on your hotfix process if it’s easier for you.</li><li>Only ship your major update merge/pull request changes</li><li>Wait the merge/pull request CI/CD pipeline, and follow your deployment flow to the production 🚀 .</li></ul><h3>🧹 Post deploy tasks</h3><p>You can now <strong>merge your branch into your main branch</strong>. Pay attention if it breaks your CI, you can have breaking changes with a commit done between the release and your change.</p><p>Keep an eye on metrics and logs after and during deployment, and on production post deployment tests.</p><p>Issues may still happen, even with all the care we put to avoid them. Having the proper observability tools, monitoring / alerting system, and the ability to quickly rollback things, is the key. You can consider doing another release, or hotfix if needed too.</p><p>Another nice thing to do is to communicate with your backend team about new changes that the major updates bring. It may be the occasion to do a presentation, or a blog post like this one 😅.</p><p>New features are always appreciated by developers and allows us to appropriate and learn new ways of coding, and get the opportunity to modernize the codebase.</p><p>You can also create tasks to handle new deprecation issues that the major update could bring. Anticipating is the key to ease the next major releases.</p><p>🎉 Congratulation!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=490ed55c54a1" width="1" height="1" alt=""><hr><p><a href="https://medium.com/yousign-engineering-product/deal-with-major-upgrades-in-php-490ed55c54a1">Deal with major upgrades in PHP</a> was originally published in <a href="https://medium.com/yousign-engineering-product">Yousign Engineering &amp; Product</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>