<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mark Railton</title>
    <description>The latest articles on DEV Community by Mark Railton (@markrailton).</description>
    <link>https://dev.to/markrailton</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F94994%2F029f16d8-e0f1-4718-87c1-81621eb072b1.jpeg</url>
      <title>DEV Community: Mark Railton</title>
      <link>https://dev.to/markrailton</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/markrailton"/>
    <language>en</language>
    <item>
      <title>Comparing strings that may or may not contain diacritics in PHP</title>
      <dc:creator>Mark Railton</dc:creator>
      <pubDate>Fri, 06 Aug 2021 23:30:42 +0000</pubDate>
      <link>https://dev.to/markrailton/comparing-strings-that-may-or-may-not-contain-diacritics-in-php-5eg1</link>
      <guid>https://dev.to/markrailton/comparing-strings-that-may-or-may-not-contain-diacritics-in-php-5eg1</guid>
      <description>&lt;p&gt;Today I ran into something that really had me scratching my head, I had to compare a string from a form against a string from the database. Clearly that's not where the issue was as it's a pretty simple thing in PHP, what had me scratching my head was that I needed to account for &lt;a href="https://en.wikipedia.org/wiki/Diacritic"&gt;diacritics&lt;/a&gt; possibly being in 1 string but not in the other.&lt;/p&gt;

&lt;p&gt;I spent quite some time looking online but eventually took to twitter and asked the wondrous PHP community for help&lt;br&gt;
&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Ok, taking a complete blank and need some &lt;a href="https://twitter.com/hashtag/php?src=hash&amp;amp;ref_src=twsrc%5Etfw"&gt;#php&lt;/a&gt; help. Need to compare 2 strings that may or may not contain diacritics. Example, Seán matches Sean. Don't know why I can't figure this one out, anyone any ideas?&lt;/p&gt;— Mark Railton (@railto) &lt;a href="https://twitter.com/railto/status/1423661524883812355?ref_src=twsrc%5Etfw"&gt;August 6, 2021&lt;/a&gt;
&lt;/blockquote&gt;  

&lt;p&gt;Within minutes I had a couple of people offering suggestions and health conversation ensued. I settled on a &lt;a href="https://twitter.com/derickr/status/1423665598832254977"&gt;solution&lt;/a&gt; by  &lt;a href="https://twitter.com/derickr"&gt;Derick Rethans&lt;/a&gt; That uses the &lt;a href="http://docs.php.net/manual/en/class.collator.php"&gt;Collator&lt;/a&gt; class from the &lt;code&gt;intl&lt;/code&gt; extension. I took the example provided by Derick and tweaked it just a bit to suit how I wanted it, snippet of which is below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Collator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s1"&gt;'en'&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$c&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setStrength&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nc"&gt;Collator&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;PRIMARY&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$c&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getSortKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$newUser&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'firstname'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nv"&gt;$c&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getSortKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$existingUser&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;firstname&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To give a bit more context on this, Let's say we have a user called Sean. Sometimes people called Sean will spell it &lt;code&gt;Sean&lt;/code&gt; but others may spell it &lt;code&gt;Seán&lt;/code&gt; with the Irish diacritic &lt;code&gt;Fada&lt;/code&gt;. Both of these people are called Sean and both spellings are seen as correct, however when doing a direct comparison in PHP (or any other language really) you'll end up getting a mismatch if you try using the equals operator. For the task I've been working on, it was important that we allow for the same person possibly having the Fada in their name in the database, but then maybe not entering it another time in a different form. &lt;/p&gt;

&lt;p&gt;Thanks to Derick, Ben and the others that posted possible solutions on the twitter thread. It really helped and thankfully I was able to move on with the task.&lt;/p&gt;

</description>
      <category>php</category>
    </item>
    <item>
      <title>Using Tailwind CSS and PurgeCSS with Symfony Encore</title>
      <dc:creator>Mark Railton</dc:creator>
      <pubDate>Sun, 30 Aug 2020 21:08:38 +0000</pubDate>
      <link>https://dev.to/markrailton/using-tailwind-css-and-purgecss-with-symfony-encore-5cgj</link>
      <guid>https://dev.to/markrailton/using-tailwind-css-and-purgecss-with-symfony-encore-5cgj</guid>
      <description>&lt;p&gt;This was originally posted on my own website at &lt;a href="https://markrailton.com/blog/using-tailwind-css-and-purgecss-with-symfony-encore"&gt;markrailton.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Recently I've started playing around with the &lt;a href="https://symfony.com"&gt;Symfony&lt;/a&gt; framework as a more lightweight alternative to Laravel (in case you didn't know, Laravel contains a lot of functionality that many apps don't need and has a lot of &lt;em&gt;magic&lt;/em&gt; in the background).&lt;/p&gt;

&lt;p&gt;One thing that I really liked about Laravel was Laravel Mix, and how easy Mix made it to integrate the utility-first CSS framework &lt;a href="https://tailwindcss.com"&gt;Tailwind CSS&lt;/a&gt; and Purgecss (used for getting rid of CSS that's not needed). When I first started looking into &lt;a href="https://symfony.com/doc/current/frontend.html#webpack-encore"&gt;Symfony Encore&lt;/a&gt; I found a nice guide on the Tailwind docs about getting Tailwind up and running on Encore. This was fantastic, but, there was a massive issue. The default CSS that was being generated was way in excess of 2MB in size, something that's simply far too big. Yes, TailwindCSS has support for PurgeCSS built in, but that means that you need to run your &lt;code&gt;npm run dev&lt;/code&gt; or similar command each time you make a change that would involve changes to css.&lt;/p&gt;

&lt;p&gt;I started to look further and came across a &lt;a href="https://www.phproberto.com/en/41-integrating-purgecss-with-symfony-encore"&gt;guide&lt;/a&gt; by Roberto Segura on how to integrate Purgecss with Encore. I'll detail the steps below that will allow you to get TailwindCSS integrated to Symfony Encore using Purgecss to reduce the amount of CSS that's generated. This will assume that you have installed Symfony Encore but nothing else.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;First, let's install the dependencies, TailwindCSS, PostCSS and PurgeCSS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-D&lt;/span&gt; tailwindcss postcss-loader purgecss-webpack-plugin glob-all path
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt; &lt;/p&gt;

&lt;p&gt;Create &lt;em&gt;postcss.config.js&lt;/em&gt; in the project root with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tailwindcss&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt; &lt;/p&gt;

&lt;p&gt;Update the top of your &lt;em&gt;webpack.config.js&lt;/em&gt; file like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Encore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@symfony/webpack-encore&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PurgeCssPlugin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;purgecss-webpack-plugin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;glob&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;glob-all&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(for some reason Encore defaults to using &lt;em&gt;var&lt;/em&gt;, so I updated that too)&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;Next, update the Encore configuration chain in &lt;em&gt;webpack.config.js&lt;/em&gt; to include PostCssLoader:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;Encore&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;enablePostCssLoader&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt; &lt;/p&gt;

&lt;p&gt;So that we're not constantly having to run &lt;code&gt;npm run dev&lt;/code&gt; during development, we will add the PurgeCSS inside an if check where we make sure to only run it on production (&lt;code&gt;npm run build&lt;/code&gt;)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Encore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isProduction&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;Encore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addPlugin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;PurgeCssPlugin&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;glob&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
            &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;templates/**/*.html.twig&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;]),&lt;/span&gt;
        &lt;span class="na"&gt;defaultExtractor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;[\w&lt;/span&gt;&lt;span class="sr"&gt;-&lt;/span&gt;&lt;span class="se"&gt;/&lt;/span&gt;&lt;span class="sr"&gt;:&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;(?&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;!:&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, you need to update your &lt;em&gt;assets/css/app.css&lt;/em&gt; to load Tailwind:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="s1"&gt;"tailwindcss/base"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="s1"&gt;"tailwindcss/components"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="s1"&gt;"tailwindcss/utilities"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt; &lt;/p&gt;

&lt;p&gt;Now, by running Encore, your CSS will be generated with TailwindCSS and only the required CSS will be created:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt; &lt;/p&gt;

&lt;p&gt;You can also use the &lt;em&gt;watch&lt;/em&gt; command to keep an eye on your CSS and JS files so that you can get fresh copies of your assets built each time you make a change, simply use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run watch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>symfony</category>
      <category>tailwindcss</category>
      <category>postcss</category>
      <category>purgecss</category>
    </item>
    <item>
      <title>A simple act goes a long way</title>
      <dc:creator>Mark Railton</dc:creator>
      <pubDate>Mon, 27 Apr 2020 08:34:10 +0000</pubDate>
      <link>https://dev.to/markrailton/a-simple-act-goes-a-long-way-5b8m</link>
      <guid>https://dev.to/markrailton/a-simple-act-goes-a-long-way-5b8m</guid>
      <description>&lt;h6&gt;
  
  
  This was originally posted on my personal site &lt;a href="https://markrailton.com/blog/2020/04/a-simple-act-goes-a-long-way"&gt;here&lt;/a&gt;
&lt;/h6&gt;

&lt;p&gt;Four years ago I was taking part in a coding boot camp called &lt;a href="https://codeinstitute.net"&gt;Code Institute&lt;/a&gt;. At the time I had already been working as a web developer for just under a year and a half, but I was self taught and felt extremely limited in what I knew and was able to achieve. I've been meaning to do a write up about my time with Code Institute, but that is not this post, hopefully soon though.&lt;/p&gt;

&lt;p&gt;Today I want to talk about Boggle, a word game that I was never really that good at, but always enticed by. If you've no idea what I'm talking about, then maybe take a look &lt;a href="https://en.wikipedia.org/wiki/Boggle"&gt;here&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;When I was taking part in Code Institute's boot camp, the 2nd stream of study was Python, a language that, until that point, I knew nothing about. During the Python module there was a sort of mini project, to build a clone of the game Boggle that would draw the 4 * 4 grid of letter tiles and also give a list of valid words that could be generated via the 16 characters that were on screen. &lt;/p&gt;

&lt;p&gt;I honestly can't remember how long I spent working on the game (I didn't put it under git until after I completed it), but I know it wasn't all that long. I completed the basic requirements and put it up on &lt;a href="https://github.com/railto/boggle-solver"&gt;GitHub&lt;/a&gt; then promptly forgot about it, until this week. A few days ago I got an email from GitHub saying a new pull request had been opened against the project and, if I'm honest, it really took me by surprise. I had completely forgotten about the project and wondered why anyone would be looking at it, never mind submitting a PR against it, after all, there wasn't even a readme on the repository to explain what it was.&lt;/p&gt;

&lt;p&gt;I had a look at the &lt;a href="https://github.com/railto/boggle-solver/pull/1"&gt;submitted change&lt;/a&gt; and initially thought about just closing it and maybe deleting the project seeing as I clearly didn't use it. The next day I got another email, the change author had added a &lt;a href="https://github.com/railto/boggle-solver/pull/1#issuecomment-619059038"&gt;message to the pull request &lt;/a&gt; thanking me for the project and that he had used it to play boggle on a conference call with around a dozen people and it had made scoring simple. I looked at the committed changes again and realised I'd made a pretty big error when creating the game. The physical game uses a grid of 16 dice, each die has 6 letters. In my version of the game however, I wasn't using the concept of dice, instead I was picking 16 random characters out of the English alphabet, so theoretically it was possible to get combinations of letters in my version that were not possible in the physical version.&lt;/p&gt;

&lt;p&gt;After poking around at the code I realised that the changes made much more sense in the context of how the physical game is played. Not only had this person modified it to use dice instead of just random characters, he'd also added in the score for each word to make things even easier. At this point I decided that I'd definitely pull in his changes as they really made sense and made the game more complete. I asked for 1 relatively minor tweak and once that was done I merged the change. I also decided to finally include a readme and license for the game, two things that are pretty much a requirement for anything that's on GitHub these days.&lt;/p&gt;

&lt;p&gt;So, why am I writing about this? Well, the whole thing got me thinking about how what we do as developers, whilst maybe insignificant at the time, has the ability to impact others in a way that we can't even begin to think about.  The author of the pull request, a guy called Brian from Missouri whom I'd never met or even spoken to, had searched online for 'Python Boggle Solver' and my code repository was the first that came up in the search results. Not only was my code the first result that came up, but it was useful for what he was wanting to achieve. What made it even more 'real' for me, is that he was using code I wrote to help with breaking the monotony of not being able to leave home and spend some time playing a game with others during a conference call.&lt;/p&gt;

&lt;p&gt;The simple act of opening a pull request let me know that code I created around 4 years ago was able to help someone, and during these difficult times, it gave me a much needed boost. If you have come across some code or a blog article recently that's helped you, please consider just dropping a note of thanks to whomever created the code or article, you never know, it might just make their day.&lt;/p&gt;

</description>
      <category>mentalhealth</category>
      <category>developerlife</category>
      <category>boggle</category>
    </item>
    <item>
      <title>Creating migrations when changing an enum in Python using SQLAlchemy</title>
      <dc:creator>Mark Railton</dc:creator>
      <pubDate>Sun, 29 Mar 2020 16:41:26 +0000</pubDate>
      <link>https://dev.to/markrailton/creating-migrations-when-changing-an-enum-in-python-using-sqlalchemy-5fna</link>
      <guid>https://dev.to/markrailton/creating-migrations-when-changing-an-enum-in-python-using-sqlalchemy-5fna</guid>
      <description>&lt;p&gt;This was originally posted on my own blog &lt;a href="https://markrailton.com/blog/creating-migrations-when-changing-an-enum-in-python-using-sql-alchemy"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Recently at work I've spent some time working on a scaffold project that we'll be using for API projects that we'll be building.&lt;/p&gt;

&lt;p&gt;For a number of reasons we've decided to use Python as our backend language and Flask as our API framework. One of the things I love most about Flask is that it's very unopinionated and let's you build what you want, pretty much how you want.&lt;/p&gt;

&lt;p&gt;One of the features I've been working on is an audit log. For data integrity purposes we decided to use an enum field for the &lt;code&gt;event type&lt;/code&gt; value in both the code itself and also in the database. Like many Flask applications, we're using SQLAlchemy as an ORM and Flask-Migrate to automatically create Alembic migrations. Using a SQLAlchemy model with the field type set to an enum equal to the enum used in the code, I had expected Flask-Migrate to automatically create a new migration any time we added values to the EventType enum class, however this is not the case.&lt;/p&gt;

&lt;p&gt;After some searching around, I discovered that this is a known issue with Alembic and that migrations for enum changes have to be created manually. I've got a sample migration that I created manually below as well as some steps so you can see how to handle adding or removing a value from an enum in Flask. Note that this migration is specifically written to work with PostgreSQL as that is the database engine that we use.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Make changes to the Enum in the relevant model&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create an empty migration file&lt;br&gt;
&lt;br&gt;
&lt;code&gt;flask db revision -m 'Add Logout_Success to AuditEvent'&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Populate the new migration with code to create the changes, note you will need to add values for the existing and new options ensuring to keep the revision and down_revision numbers that already exist in the new migration file&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="s"&gt;"""
Add Logout_Success to AuditEvent

Revision ID: 08720b8a9d11
Revises: 810eac468f83
Create Date: 2020-03-25 12:19:09.432635

"""&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;alembic&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;sqlalchemy&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;sa&lt;/span&gt;

&lt;span class="c1"&gt;# revision identifiers, used by Alembic.
&lt;/span&gt;&lt;span class="n"&gt;revision&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'08720b8a9d11'&lt;/span&gt;
&lt;span class="n"&gt;down_revision&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'810eac468f83'&lt;/span&gt;
&lt;span class="n"&gt;branch_labels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;span class="n"&gt;depends_on&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

&lt;span class="c1"&gt;# Enum 'type' for PostgreSQL
&lt;/span&gt;&lt;span class="n"&gt;enum_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'auditevent'&lt;/span&gt;
&lt;span class="c1"&gt;# Set temporary enum 'type' for PostgreSQL
&lt;/span&gt;&lt;span class="n"&gt;tmp_enum_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'tmp_'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;enum_name&lt;/span&gt;

&lt;span class="c1"&gt;# Options for Enum
&lt;/span&gt;&lt;span class="n"&gt;old_options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'LOGIN_SUCCESS'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'LOGIN_FAIL'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;new_options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;old_options&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'LOGOUT_SUCCESS'&lt;/span&gt;&lt;span class="p"&gt;,))&lt;/span&gt;

&lt;span class="c1"&gt;# Create enum fields
&lt;/span&gt;&lt;span class="n"&gt;old_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Enum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;old_options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;enum_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;new_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Enum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;new_options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;enum_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;upgrade&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="c1"&gt;# Rename current enum type to tmp_
&lt;/span&gt;    &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'ALTER TYPE '&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;enum_name&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;' RENAME TO '&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;tmp_enum_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# Create new enum type in db
&lt;/span&gt;    &lt;span class="n"&gt;new_type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_bind&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="c1"&gt;# Update column to use new enum type
&lt;/span&gt;    &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'ALTER TABLE audit ALTER COLUMN event_type TYPE '&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;enum_name&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;' USING event_type::text::'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;enum_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# Drop old enum type
&lt;/span&gt;    &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'DROP TYPE '&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;tmp_enum_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;downgrade&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="c1"&gt;# Instantiate db query
&lt;/span&gt;    &lt;span class="n"&gt;audit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'audit'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'event_type'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nullable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="c1"&gt;# Convert LOGOUT_SUCCESS to LOGIN_SUCCESS (this is just a sample so may not make sense)
&lt;/span&gt;    &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;audit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;audit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;event_type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sa"&gt;u&lt;/span&gt;&lt;span class="s"&gt;'LOGOUT_SUCCESS'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'LOGIN_SUCCESS'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="c1"&gt;# Rename enum type to tmp_
&lt;/span&gt;    &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'ALTER TYPE '&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;enum_name&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;' RENAME TO '&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;tmp_enum_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# Create enum type using old values
&lt;/span&gt;    &lt;span class="n"&gt;old_type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_bind&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="c1"&gt;# Set enum type as type for event_type column
&lt;/span&gt;    &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'ALTER TABLE audit ALTER COLUMN event_type TYPE '&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;enum_name&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;' USING event_type::text::'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;enum_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# Drop temp enum type
&lt;/span&gt;    &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'DROP TYPE '&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;tmp_enum_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hopefully this will be of use to someone.&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>alembic</category>
      <category>enum</category>
      <category>sqlalchemy</category>
    </item>
  </channel>
</rss>
