<?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>Forem: Ricardo Čerljenko</title>
    <description>The latest articles on Forem by Ricardo Čerljenko (@rcerljenko).</description>
    <link>https://forem.com/rcerljenko</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%2F375926%2Fd6910f2d-3ae0-42df-895e-1f8df59df44c.jpeg</url>
      <title>Forem: Ricardo Čerljenko</title>
      <link>https://forem.com/rcerljenko</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/rcerljenko"/>
    <language>en</language>
    <item>
      <title>Use Laravel with OpenAI to validate inappropriate content</title>
      <dc:creator>Ricardo Čerljenko</dc:creator>
      <pubDate>Fri, 10 Feb 2023 20:40:29 +0000</pubDate>
      <link>https://forem.com/lloyds-digital/use-laravel-with-openai-to-validate-inappropriate-content-2e67</link>
      <guid>https://forem.com/lloyds-digital/use-laravel-with-openai-to-validate-inappropriate-content-2e67</guid>
      <description>&lt;p&gt;Recently I stumbled across &lt;a href="https://platform.openai.com/docs/api-reference/moderations" rel="noopener noreferrer"&gt;OpenAI Moderations API&lt;/a&gt; which gives you a way to query OpenAI in order to detect if input text contains inappropriate content such as hate, violence, etc.&lt;/p&gt;

&lt;p&gt;API is completly free - you just need to create an OpenAI account and issue a fresh API token.&lt;/p&gt;

&lt;p&gt;Since I'm primary a Laravel PHP Framework developer, I decided to &lt;a href="https://github.com/rcerljenko/laravel-openai-moderation" rel="noopener noreferrer"&gt;make a package&lt;/a&gt; which will provide a way to validate request payload fields against OpenAI Moderations API.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installation
&lt;/h3&gt;

&lt;p&gt;Standard &lt;a href="https://getcomposer.org/download" rel="noopener noreferrer"&gt;Composer&lt;/a&gt; package installation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer require rcerljenko/laravel-openai-moderation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Usage
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Publish config and translation files.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php artisan vendor:publish &lt;span class="nt"&gt;--provider&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"RCerljenko&lt;/span&gt;&lt;span class="se"&gt;\L&lt;/span&gt;&lt;span class="s2"&gt;aravelOpenAIModeration&lt;/span&gt;&lt;span class="se"&gt;\L&lt;/span&gt;&lt;span class="s2"&gt;aravelOpenAIModerationServiceProvider"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Set your OpenAI API key and enable package via newly created config file =&amp;gt; &lt;code&gt;config/openai.php&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use provided rule with your validation rules.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Http\Requests&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Foundation\Http\FormRequest&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;RCerljenko\LaravelOpenAIModeration\Rules\OpenAIModeration&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;StoreText&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;FormRequest&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="cd"&gt;/**
  * Determine if the user is authorized to make this request.
  */&lt;/span&gt;
 &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;authorize&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;bool&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;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;

 &lt;span class="cd"&gt;/**
  * Get the validation rules that apply to the request.
  */&lt;/span&gt;
 &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt;
 &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
   &lt;span class="s1"&gt;'text'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'required'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'string'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OpenAIModeration&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;And that's it! Your content can now be validated with powerfull (and yet free) OpenAI Moderations API.&lt;/p&gt;

&lt;p&gt;Thank you for reading this! If you've found this interesting, consider leaving a ❤️, 🦄 , and of course, share and comment on your thoughts!&lt;/p&gt;

&lt;p&gt;Lloyds is available for partnerships and open for new projects. If you want to know more about us, &lt;a href="https://lloyds-digital.com" rel="noopener noreferrer"&gt;check us out&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Also, don’t forget to follow us on &lt;a href="https://instagram.com/lloyds.digital" rel="noopener noreferrer"&gt;Instagram&lt;/a&gt; and &lt;a href="https://facebook.com/lloydsdigital" rel="noopener noreferrer"&gt;Facebook&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>remote</category>
      <category>startup</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Laravel - Serve API requests with translated validation rules</title>
      <dc:creator>Ricardo Čerljenko</dc:creator>
      <pubDate>Wed, 19 Oct 2022 18:49:32 +0000</pubDate>
      <link>https://forem.com/lloyds-digital/laravel-serve-api-requests-with-translated-validation-rules-1c6o</link>
      <guid>https://forem.com/lloyds-digital/laravel-serve-api-requests-with-translated-validation-rules-1c6o</guid>
      <description>&lt;p&gt;Consider building a mobile app (or a website) which connects to a Laravel CMS over API for dynamic content. Now, the app can be a multi-language app which expects to receive a translated content from the CMS.&lt;br&gt;
Usually, in our company, we instruct our frontend developers to send a &lt;code&gt;lang&lt;/code&gt; query param on every request in order to deliver the correct translated content back.&lt;/p&gt;

&lt;p&gt;E.g.:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET /api/blogs?lang=en
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, Laravel validation is not aware of this and it always returns validation error messages according to app locale (or fallback locale).&lt;/p&gt;

&lt;p&gt;Therefore we created a route middleware which groups all API routes and sets app locale based on the &lt;code&gt;lang&lt;/code&gt; query param:&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="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Http\Middleware&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Closure&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Http\Request&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Symfony\Component\HttpFoundation\Response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ChangeLocale&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/**
     * Handle an incoming request.
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Closure&lt;/span&gt; &lt;span class="nv"&gt;$next&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;Response&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$locale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'lang'&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;$locale&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;app&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;setLocale&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$locale&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="nv"&gt;$next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$request&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;And in routes file:&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="c1"&gt;// routes/api.php&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Http\Middleware\ChangeLocale&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Support\Facades\Route&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ChangeLocale&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;group&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ROUTES&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now your validation messages will be in the requested locale. If you don't like handling this over query param you can always use a header or something else, e.g.:&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;$locale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Accept-Language'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Thank you for reading this! If you've found this interesting, consider leaving a ❤️, 🦄 , and of course, share and comment on your thoughts!&lt;/p&gt;

&lt;p&gt;Lloyds is available for partnerships and open for new projects. If you want to know more about us, &lt;a href="https://lloyds-digital.com"&gt;check us out&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Also, don’t forget to follow us on &lt;a href="https://instagram.com/lloyds.digital"&gt;Instagram&lt;/a&gt; and &lt;a href="https://facebook.com/lloydsdigital"&gt;Facebook&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>php</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Creating a Neat DateTime Helper Function in PHP</title>
      <dc:creator>Ricardo Čerljenko</dc:creator>
      <pubDate>Thu, 24 Mar 2022 12:35:05 +0000</pubDate>
      <link>https://forem.com/lloyds-digital/creating-a-neat-datetime-helper-function-in-php-45in</link>
      <guid>https://forem.com/lloyds-digital/creating-a-neat-datetime-helper-function-in-php-45in</guid>
      <description>&lt;p&gt;Let me start with a statement: I'm not a big fan of global helper functions being included in the project, but sometimes it's a good thing to have that little helper functions here and there.&lt;/p&gt;

&lt;p&gt;Working with datetime in PHP could be a real pain if you don't take advantage of popular libraries like &lt;a href="https://carbon.nesbot.com"&gt;Carbon&lt;/a&gt;. It's all good until you have to convert dates provided on user input into another timezone (eg. UTC) and vice versa. Other example could be that you have to manage various input datetime formats, and sanitize them into a consistent one before saving it to database.&lt;/p&gt;

&lt;p&gt;I will show you how I handled that by creating a datetime helper function which will take any datetime format and convert it into a consistent one with the power of Carbon library.&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="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Carbon\Carbon&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;formatDateTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="kt"&gt;DateTimeInterface&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;float&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$inputDateTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$outputFormat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Y-m-d H:i:s'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kt"&gt;DateTimeZone&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$outputTimezone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'UTC'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kt"&gt;DateTimeZone&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$inputTimezone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'UTC'&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$carbon&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;is_numeric&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$inputDateTime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="nc"&gt;Carbon&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;createFromTimestamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$inputDateTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$inputTimezone&lt;/span&gt;&lt;span class="p"&gt;)&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;Carbon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$inputDateTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$inputTimezone&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$carbon&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setTimezone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$outputTimezone&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$outputFormat&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;Let's go over this bit by bit. The function takes 4 arguments and none of them are required which means that if called without any argument, the function should return a current UTC datetime string in a common database format.&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;$date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;formatDateTime&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="c1"&gt;// 2022-02-03 08:10:21&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First argument &lt;code&gt;$inputDateTime&lt;/code&gt; is the most important one and by its signature you can easily figure out that it can accept various datetime formats including a string, float, integer and a &lt;code&gt;DateTimeInterface&lt;/code&gt; capable object. That last one is important because it enables us to work with any PHP datetime object as well as any potential library that implements that interface (such as Carbon).&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="c1"&gt;// string&lt;/span&gt;
&lt;span class="nv"&gt;$date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;formatDateTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'2022-02-03 08:10:21'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// string&lt;/span&gt;
&lt;span class="nv"&gt;$date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;formatDateTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'2022-12-31'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// int (UNIX timestamp)&lt;/span&gt;
&lt;span class="nv"&gt;$date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;formatDateTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="c1"&gt;// float (UNIX timestamp in microseconds)&lt;/span&gt;
&lt;span class="nv"&gt;$date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;formatDateTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;microtime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// DateTime object&lt;/span&gt;
&lt;span class="nv"&gt;$date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;formatDateTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Carbon object&lt;/span&gt;
&lt;span class="nv"&gt;$date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;formatDateTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Carbon&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Laravel Carbon datetime casting&lt;/span&gt;
&lt;span class="nv"&gt;$date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;formatDateTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$post&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;created_at&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Other arguments are pretty self-explanatory.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$outputFormat&lt;/code&gt; controls in which format will function return the datetime string, e.g.:&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;$date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;formatDateTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'d/m/Y'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// 03/02/2022&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;$outputTimezone&lt;/code&gt; controls the result timezone and &lt;code&gt;$inputTimezone&lt;/code&gt; tells the function in which timezone is the &lt;code&gt;$inputDateTime&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you're running under PHP8+ then it's even easier to handle arguments with the "named arguments" feature like so:&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;$date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;formatDateTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;inputTimezone&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'Europe/Zagreb'&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Thank you for reading this! If you've found this interesting, consider leaving a ❤️, 🦄 , and of course, share and comment on your thoughts!&lt;/p&gt;

&lt;p&gt;Lloyds is available for partnerships and open for new projects. If you want to know more about us, &lt;a href="https://lloyds-digital.com"&gt;check us out&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Also, don’t forget to follow us on &lt;a href="https://instagram.com/lloyds.digital"&gt;Instagram&lt;/a&gt; and &lt;a href="https://facebook.com/lloydsdigital"&gt;Facebook&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>php</category>
      <category>datetime</category>
      <category>webdev</category>
      <category>carbon</category>
    </item>
    <item>
      <title>How to handle both API and Basic authentication in Laravel</title>
      <dc:creator>Ricardo Čerljenko</dc:creator>
      <pubDate>Thu, 03 Mar 2022 09:55:42 +0000</pubDate>
      <link>https://forem.com/lloyds-digital/how-to-handle-both-api-and-basic-authentication-in-laravel-1bgc</link>
      <guid>https://forem.com/lloyds-digital/how-to-handle-both-api-and-basic-authentication-in-laravel-1bgc</guid>
      <description>&lt;p&gt;While building your app in Laravel PHP Framework, you have multiple ways of protecting your API routes with various auth guards or Basic auth. Would it be nice to support both API guard and Basic auth at the same time?&lt;/p&gt;

&lt;p&gt;In default Laravel app you can protect your API routes like this:&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="c1"&gt;// routes/api.php&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Support\Facades\Route&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'auth:api'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;group&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// PROTECTED ROUTES&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or using Basic auth:&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="c1"&gt;// routes/api.php&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Support\Facades\Route&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'auth.basic'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;group&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// PROTECTED ROUTES&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But it's not possible to guard your routes with both of them. E.g., if there's no provided Bearer token use the Basic auth. To accomplish this we need to make some adjustments to the default &lt;code&gt;Authenticate&lt;/code&gt; middleware which is provided in the &lt;code&gt;app/Http/Middleware&lt;/code&gt; directory. Here's how I achieved that:&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="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Http\Middleware&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Closure&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Auth\AuthenticationException&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Symfony\Component\HttpFoundation\Response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Auth\Middleware\Authenticate&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nc"&gt;Middleware&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Authenticate&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Middleware&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/**
     * Handle an incoming request.
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Closure&lt;/span&gt; &lt;span class="nv"&gt;$next&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nv"&gt;$guards&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;Response&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;authenticate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$guards&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;AuthenticationException&lt;/span&gt; &lt;span class="nv"&gt;$e&lt;/span&gt;&lt;span class="p"&gt;)&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="o"&gt;!&lt;/span&gt;&lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;wantsJson&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nv"&gt;$e&lt;/span&gt;&lt;span class="p"&gt;;&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;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;onceBasic&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="nv"&gt;$response&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="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$request&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;First, we catch the &lt;code&gt;AuthenticationException&lt;/code&gt; which is thrown by the parent &lt;code&gt;authenticate()&lt;/code&gt; method. That means that every provided guard (or a default one) didn't produce a valid user.&lt;/p&gt;

&lt;p&gt;Now we can try to do a Basic auth but only if the client expects a JSON response (we don't want to try Basic auth in a normal web context because it would pop-up the Basic auth prompt box on every browser request).&lt;/p&gt;

&lt;p&gt;Take note that &lt;code&gt;onceBasic()&lt;/code&gt; method returns &lt;code&gt;null&lt;/code&gt; if the provided Basic auth credentials are valid. If not, it returns an already formed Error Response bag which you can safely return from the middleware.&lt;/p&gt;

&lt;p&gt;Now we're able to authenticate our users on API routes with both API guard and fallback Basic auth by simply using a default &lt;code&gt;auth&lt;/code&gt; middleware.&lt;/p&gt;

&lt;p&gt;Thank you for reading this! If you've found this interesting, consider leaving a ❤️, 🦄 , and of course, share and comment on your thoughts!&lt;/p&gt;

&lt;p&gt;Lloyds is available for partnerships and open for new projects. If you want to know more about us, &lt;a href="https://lloyds-digital.com"&gt;check us out&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Also, don’t forget to follow us on &lt;a href="https://instagram.com/lloyds.digital"&gt;Instagram&lt;/a&gt; and &lt;a href="https://facebook.com/lloydsdigital"&gt;Facebook&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>auth</category>
      <category>webdev</category>
      <category>php</category>
    </item>
    <item>
      <title>PHP Laravel Local Dev Setup</title>
      <dc:creator>Ricardo Čerljenko</dc:creator>
      <pubDate>Mon, 05 Oct 2020 08:53:19 +0000</pubDate>
      <link>https://forem.com/lloyds-digital/php-laravel-local-dev-setup-4l10</link>
      <guid>https://forem.com/lloyds-digital/php-laravel-local-dev-setup-4l10</guid>
      <description>&lt;p&gt;Coming from a company that has multiple backend developers and even more ongoing projects, it's a normal situation that developers are shared between multiple projects. From the developers point of view that's not the ideal scenario because there will always be a "context switch" time penalty where you have to disengage yourself from you current state of mind and integrate your focus to a completely new project. That includes reading the user stories and tasks that are left to be done on this new project as well as understanding the code itself that the previous developer left on.&lt;/p&gt;

&lt;p&gt;While we can't do much about the first part where your teammates must somehow onboard you to the new project, there are some things that we can do with our codebase so that any developer in the company can understand it with ease. Over the past few years we figured out that some developers find it very hard to continue on someone else's code if they vary a lot in coding style - it somehow feels unnatural and wrong don't you agree? There's also a problem of structuring your codebase, especially when you're working with frameworks such as Laravel where you have a multiple ways to achieve the same thing.&lt;/p&gt;

&lt;p&gt;Here are some pieces of advice on how we can minimize the differences between coding styles and project structures that we implemented over the past few years.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Master project template
&lt;/h2&gt;

&lt;p&gt;In our company we have around 15 developers in three developer divisions: Backend Development (&lt;a href="https://laravel.com"&gt;Laravel PHP Framework&lt;/a&gt;), Frontend Web Development (&lt;a href="https://nuxtjs.org"&gt;Nuxt.js Framework&lt;/a&gt;) and Mobile App Development (&lt;a href="https://reactnative.dev"&gt;React Native&lt;/a&gt;). Imagine that every developer starts it's project completely on its own without any guidelines and completely from scratch every time. It would be a mess out there. No one could jump in in the middle of the project and continue to work without that person sitting by its side.&lt;/p&gt;

&lt;p&gt;Instead, let's create a "Master template" (some companies call that "skeleton project" or "base template") which will be a starting point for all future projects of that division. So in our case, we have a Laravel, Nuxt.js, and React Native master templates and all projects originate from them. Master templates have to be maintained (usually by a team lead) and updated from time to time especially when a new framework version gets out. Templates contain everything that you need to start a fresh new project (eg. UI kit, auth, base controllers and logic, database setup, settings, user management, ...).&lt;/p&gt;

&lt;p&gt;Once every developer gets familiarized with the template it's a lot easier to switch to a new project because you know where you can find your Models, Controllers, Custom logic, etc.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Enforce coding style
&lt;/h2&gt;

&lt;p&gt;Every developer has its coding style which can be a problem in a shared project sense. Some tools that can help you set up a set of rules that developers have to obey in their coding. You have to think in a way to achieve a silver lining so that most of the team is satisfied with that.&lt;/p&gt;

&lt;h3&gt;
  
  
  PHP
&lt;/h3&gt;

&lt;p&gt;One of the most popular tools in PHP is &lt;a href="https://github.com/FriendsOfPHP/PHP-CS-Fixer"&gt;PHP Coding Standards Fixer&lt;/a&gt;. You can read all about it in the documentation but at this point the developer would have to manually fix its code once in a while. Down the road we'll learn how we can achieve that automatically.&lt;/p&gt;

&lt;h3&gt;
  
  
  JavaScript
&lt;/h3&gt;

&lt;p&gt;For JS we chose &lt;a href="https://prettier.io"&gt;Prettier&lt;/a&gt;, one of the most popular libraries for JS code formatting. Again at this point developer should also do this manually once in a while.&lt;/p&gt;

&lt;p&gt;Both tools have their own set of rules which I strongly encourage you to take a look at (especially PHP CS Fixer) and tweak it to your needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Static analysis of the code
&lt;/h2&gt;

&lt;p&gt;This step is the important one. We can leverage from the tool called &lt;a href="https://github.com/nunomaduro/larastan"&gt;Larastan&lt;/a&gt; which is basically a wrapper for &lt;a href="https://github.com/phpstan/phpstan"&gt;PHPStan&lt;/a&gt; with Laravel specific config. The tool will perform a static analysis of our code and find out if we have some errors that we simply didn't catch but they will pop up in the runtime for sure and crash our app.&lt;br&gt;
Like in the steps above, the developer has to do that manually in order to scan the code.&lt;/p&gt;
&lt;h2&gt;
  
  
  4. Combine and automate
&lt;/h2&gt;

&lt;p&gt;Wouldn't be nice if we could completely automate steps 2. and 3. before every git commit? Yes we can and that's exactly what we're going to do. Before every commit, we're going to scan our entire code, fix the coding style according to our rule set in both PHP and JS, and run the static analysis of the code to catch any hidden errors. On top of that if any of that step catches something, we're not going to let the commit to happen. Instead, we'll force the user to fix the errors and repeat the commit again.&lt;/p&gt;

&lt;p&gt;First, we need to set up our "pre-commit" hook that will react every time user wants to commit something. The easiest way for that is to use the package called &lt;a href="https://github.com/BrainMaestro/composer-git-hooks"&gt;brainmaestro/composer-git-hooks&lt;/a&gt;. The package has installation instructions that allows you to add a custom git hooks on some events like "pre-commit".&lt;br&gt;
After including the package in your &lt;code&gt;composer.json&lt;/code&gt; file you should update your &lt;code&gt;scripts&lt;/code&gt; section and add something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"post-install-cmd"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cghooks add --ignore-lock"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"post-update-cmd"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cghooks update"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It means that the hooks will be updated after each &lt;code&gt;composer install&lt;/code&gt; and &lt;code&gt;composer update&lt;/code&gt; events. While we're here, for the ease of this example, we could also add our custom scripts for steps 2. and 3. like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"check-format"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"php-cs-fixer fix --dry-run"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"format"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"php-cs-fixer fix"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"analyse"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"phpstan analyse"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And in &lt;code&gt;package.json&lt;/code&gt; for the JS fixer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"check-format"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"prettier --check resources/assets/js/**/*.js"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"format"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"prettier --write resources/assets/js/**/*.js"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With that few scripts we can do this now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# scans the PHP code and reports for invalid coding style&lt;/span&gt;
composer check-format

&lt;span class="c"&gt;# fixes the invalid PHP coding style&lt;/span&gt;
composer format

&lt;span class="c"&gt;# scans the JS code and reports for invalid coding style&lt;/span&gt;
npm run check-format

&lt;span class="c"&gt;# fixes the invalid JS coding style&lt;/span&gt;
npm run format

&lt;span class="c"&gt;# runs static code analysis&lt;/span&gt;
composer analyse
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now we need to instruct our script what to do when a pre-commit event happens. Let's create a custom script that will automate all of the steps above. First, add the target script in the &lt;code&gt;extra&lt;/code&gt; section of the &lt;code&gt;composer.json&lt;/code&gt; just like in the documentation of the Composer Git Hooks package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"extra"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"laravel"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"dont-discover"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"hooks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"pre-commit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./pre-commit.sh"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now create and populate the contents of the &lt;code&gt;pre-commit.sh&lt;/code&gt; script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

npm run check-format
&lt;span class="nv"&gt;PRETTIER_EXIT_CODE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$PRETTIER_EXIT_CODE&lt;/span&gt; &lt;span class="nt"&gt;-ne&lt;/span&gt; 0 &lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;then
    &lt;/span&gt;npm run format
&lt;span class="k"&gt;fi


&lt;/span&gt;composer check-format
&lt;span class="nv"&gt;CS_FIXER_EXIT_CODE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$CS_FIXER_EXIT_CODE&lt;/span&gt; &lt;span class="nt"&gt;-ne&lt;/span&gt; 0 &lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;then
    &lt;/span&gt;composer format
&lt;span class="k"&gt;fi


&lt;/span&gt;composer analyse
&lt;span class="nv"&gt;PHP_STAN_EXIT_CODE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;


&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$PRETTIER_EXIT_CODE&lt;/span&gt; &lt;span class="nt"&gt;-ne&lt;/span&gt; 0 &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$CS_FIXER_EXIT_CODE&lt;/span&gt; &lt;span class="nt"&gt;-ne&lt;/span&gt; 0 &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$PHP_STAN_EXIT_CODE&lt;/span&gt; &lt;span class="nt"&gt;-ne&lt;/span&gt; 0 &lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;exit&lt;/span&gt; &lt;span class="nt"&gt;-1&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In English the script does this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Check JS coding style&lt;/li&gt;
&lt;li&gt;If there's something to fix, fix it&lt;/li&gt;
&lt;li&gt;Check PHP coding style&lt;/li&gt;
&lt;li&gt;If there's something to fix, fix it&lt;/li&gt;
&lt;li&gt;Perform the static analysis on the code&lt;/li&gt;
&lt;li&gt;Exit with &lt;code&gt;-1&lt;/code&gt; if any of the steps above reported an error&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When pre-commit hook exits with an exit code different than &lt;code&gt;0&lt;/code&gt; it cancels the commit and user has to do it again (or fix the code first).&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Hope you had some insight into how we manage to keep our coding style and project base the same across multiple projects and developers. This can be further upgraded to third party systems like Git Actions or &lt;a href="https://styleci.io"&gt;StyleCI&lt;/a&gt; and also you can completely customize it to your needs with custom rules and regulations.&lt;/p&gt;

&lt;p&gt;Thank you for reading this! If you've found this interesting, consider leaving a ❤️, 🦄, and of course, share and comment your thoughts!&lt;/p&gt;

&lt;p&gt;Lloyds is available for partnerships and open for new projects. If you want to know more about us, click &lt;a href="https://lloyds-design.com"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Also, don’t forget to follow us on &lt;a href="https://instagram.com/lloyds.design"&gt;Instagram&lt;/a&gt; and &lt;a href="https://facebook.com/lloydsgn"&gt;Facebook&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>prettier</category>
      <category>larastan</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
