<?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: Jack Miras</title>
    <description>The latest articles on DEV Community by Jack Miras (@jackmiras).</description>
    <link>https://dev.to/jackmiras</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%2F196978%2F1914b173-4af1-4669-b89f-c2d0a252d8fb.jpeg</url>
      <title>DEV Community: Jack Miras</title>
      <link>https://dev.to/jackmiras</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jackmiras"/>
    <language>en</language>
    <item>
      <title>Tinker in Lumen: Your Ultimate Debugging Companion</title>
      <dc:creator>Jack Miras</dc:creator>
      <pubDate>Mon, 06 Nov 2023 15:32:03 +0000</pubDate>
      <link>https://dev.to/jackmiras/tinker-in-lumen-your-ultimate-debugging-companion-102e</link>
      <guid>https://dev.to/jackmiras/tinker-in-lumen-your-ultimate-debugging-companion-102e</guid>
      <description>&lt;p&gt;When working with Lumen applications, every developer anticipates that the framework will have fewer native features when compared with Laravel. Different from its counterpart, which is intended to build full-featured applications, Lumen is intended for building smaller, faster microservices and lightweight APIs.&lt;/p&gt;

&lt;p&gt;One thing not present in Lumen that I find hard to work without is a REPL. Even though the framework has fewer features than Laravel, it still offers database, cache, events, ques, and so on, but believe it or not, Lumen doesn't offer a REPL out of the box.&lt;/p&gt;

&lt;p&gt;Fortunately for us, the process of making a REPL available to a Lumen application is not complex, and we can achieve it with a few steps.&lt;/p&gt;

&lt;h3&gt;
  
  
  Content
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;What is a REPL?&lt;/li&gt;
&lt;li&gt;Require dependency&lt;/li&gt;
&lt;li&gt;Define service provider&lt;/li&gt;
&lt;li&gt;Run the tinker command&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What is a REPL?
&lt;/h3&gt;

&lt;p&gt;Before we start, let's explore what a REPL is. The acronym stands for Read-Eval-Print Loop and allows developers to enter commands or code snippets, which are then read, evaluated, and have their results printed back to the developer. This loop continues, making it an excellent tool for quickly experimenting with code, testing small pieces of code, and learning new programming languages or libraries.&lt;/p&gt;

&lt;p&gt;Tinker is a REPL built over &lt;a href="https://github.com/bobthecow/psysh"&gt;psysh&lt;/a&gt; which is a general-purpose REPL for PHP. Since a Laravel application is not plain PHP and has states, databases, caches, events, and many more complex resources specific to the framework, it's not possible to interact with the application the way one would expect just using psysh.&lt;/p&gt;

&lt;p&gt;And that's where Tinker comes into play, since it's a &lt;a href="https://github.com/bobthecow/psysh/wiki/Integrations"&gt;psysh integration&lt;/a&gt; that implements all the specifics necessary for a developer to interact with Laravel in a REPL manner, no matter the resource or feature of the framework being accessed in the REPL.&lt;/p&gt;

&lt;p&gt;If you are new to Lumen, you might wonder: Since Tinker is a Laravel REPL, why are we looking into it for a Lumen application since they are entirely different frameworks? Well, you are right; as the &lt;a href="https://lumen.laravel.com/docs/10.x#compatibility"&gt;Lumen documentation states&lt;/a&gt;, they are in fact two different frameworks with intentional incompatibilities with libraries. However, Lumen was born out of Laravel, and it shares some of its foundations with its older sibling, which in some cases means we can use Laravel dependencies in Lumen, and Tinker is one of them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Require dependency
&lt;/h3&gt;

&lt;p&gt;Now that we have an understanding of a REPL and Tinker's foundations, let's, as a first step, add Tinker as a dependency to our project. Below is the command you have to run to add Tinker as a development dependency to Lumen.&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 &lt;span class="nt"&gt;--dev&lt;/span&gt; laravel/tinker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Define service provider
&lt;/h3&gt;

&lt;p&gt;The Tinker dependency was added to the project; the next step is to register Tinker's service provider at &lt;code&gt;bootstrap/app.php&lt;/code&gt;. In Lumen, you typically register service providers in the &lt;code&gt;bootstrap/app.php&lt;/code&gt; file to enable various functionalities within your application.&lt;/p&gt;

&lt;p&gt;A service provider is a way to bind classes into the service container, configure services, and perform other setup tasks. Registering Tinker's service provider in the &lt;code&gt;bootstrap/app.php&lt;/code&gt; file is necessary to integrate the Tinker REPL into your Lumen application. By registering its service provider, you're telling Lumen to make Tinker's REPL available to you when you run the &lt;code&gt;php artisan tinker&lt;/code&gt; command.&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;$app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Laravel\Tinker\TinkerServiceProvider&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Run the tinker command
&lt;/h3&gt;

&lt;p&gt;Once the service provider is registered and Lumen has made Tinker's REPL available, you can run &lt;code&gt;php artisan tinker&lt;/code&gt; and interact with any Lumen component you need.&lt;/p&gt;




&lt;p&gt;Now your Lumen application has a REPL configured for it.&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

</description>
      <category>tinker</category>
      <category>lumen</category>
      <category>php</category>
      <category>cli</category>
    </item>
    <item>
      <title>Python – AWS Secrets Manager: Remote env vars</title>
      <dc:creator>Jack Miras</dc:creator>
      <pubDate>Thu, 18 May 2023 14:33:43 +0000</pubDate>
      <link>https://dev.to/jackmiras/python-aws-secrets-manager-remote-env-vars-n1n</link>
      <guid>https://dev.to/jackmiras/python-aws-secrets-manager-remote-env-vars-n1n</guid>
      <description>&lt;p&gt;Environment variables play a crucial role in configuring and customizing software applications. They allow developers to store sensitive information securely and adjust the behavior of their code without modifying the underlying source files. In Python, retrieving environment variables is typically a straightforward process.&lt;/p&gt;

&lt;p&gt;However, when dealing with remote environments or secrets management, the process can become more complex. This article presents a way to retrieve environment variables, with a particular focus on integrating with AWS Secrets Manager.&lt;/p&gt;

&lt;h3&gt;
  
  
  Content
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Code to be discussed&lt;/li&gt;
&lt;li&gt;The env function&lt;/li&gt;
&lt;li&gt;The get_env function&lt;/li&gt;
&lt;li&gt;The remote_environment_variable function&lt;/li&gt;
&lt;li&gt;Usage examples&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Code to be discussed
&lt;/h3&gt;

&lt;p&gt;The code provided down below consists of three main functions: &lt;code&gt;env&lt;/code&gt;, &lt;code&gt;get_env&lt;/code&gt;, and &lt;code&gt;remote_environment_variable&lt;/code&gt;, read carefully each function's implementation, try to understand its purpose and its role in retrieving environment variables.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;base64&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;b64decode&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;botocore.exceptions&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ClientError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;NoCredentialsError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                 &lt;span class="n"&gt;ParamValidationError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;configs&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;aws&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;configs.logging&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt;

&lt;span class="s"&gt;"""
Retrieves the value of an env variable from a remote source or a .env file.

:type key: str
:type default_value: str
:return: str
"""&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default_value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default_value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"false"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;


&lt;span class="s"&gt;"""
Retrieves env variable from .env and AWS Secrets Manager, giving precedence to
remote value. If both sources exist, the remote value is returned; otherwise,
.env value or default_value is used.

:type key: str
:type default_value: str
:return: str
"""&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default_value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&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;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;local_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default_value&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;remote_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;remote_environment_variable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;remote_value&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;remote_value&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;local_value&lt;/span&gt;


&lt;span class="s"&gt;"""
Retrieves env variable from AWS Secrets Manager.

:type key: str
:return: str
"""&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;remote_environment_variable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&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;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;secret_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"AWS_SECRETS_MANAGER_SECRET_ID"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;secret_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;aws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;secrets_manager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_secret_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SecretId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;secret_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ClientError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;NoCredentialsError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ParamValidationError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NoCredentialsError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ParamValidationError&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
            &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"AWS Secrets Manager: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'Error'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s"&gt;'Code'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; to secret"&lt;/span&gt;
            &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;secret_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="s"&gt;"SecretString"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;secret_dictionary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"SecretString"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;secret_dictionary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b64decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"SecretBinary"&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;secret_dictionary&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, that the code has been read, let's explore the code in detail.&lt;/p&gt;

&lt;h3&gt;
  
  
  The env function
&lt;/h3&gt;

&lt;p&gt;This function is designed to retrieve the value of an environment variable from a remote source or a &lt;code&gt;.env&lt;/code&gt; file. It provides a practical interface for accessing environment variables, with additional handling for boolean values. By utilizing the &lt;code&gt;get_env&lt;/code&gt; function internally, it ensures consistent retrieval of variables from the appropriate source.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default_value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&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;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default_value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"false"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The env function takes two parameters: &lt;code&gt;key&lt;/code&gt;, which represents the name of the environment variable to retrieve, and an optional &lt;code&gt;default_value&lt;/code&gt; that is used if the variable is not found.&lt;/p&gt;

&lt;p&gt;Within the function, it calls the &lt;code&gt;get_env&lt;/code&gt; function, passing the key and &lt;code&gt;default_value&lt;/code&gt; parameters. The return value is assigned to the &lt;code&gt;value&lt;/code&gt; variable.&lt;/p&gt;

&lt;p&gt;To provide additional flexibility, the function checks if the retrieved value is either “true” or “false”. If the value is “true” (case-insensitive), it returns a boolean &lt;code&gt;True&lt;/code&gt;. If the value is “false” (case-insensitive), it returns a boolean &lt;code&gt;False&lt;/code&gt;. This allows for more practical handling of boolean environment variables.&lt;/p&gt;

&lt;p&gt;If the value is not a boolean, the function returns the original value as a string.&lt;/p&gt;

&lt;p&gt;Overall, the &lt;code&gt;env&lt;/code&gt; function simplifies the retrieval of environment variables by utilizing the &lt;code&gt;get_env&lt;/code&gt; function internally and providing a consistent and flexible interface for accessing and interpreting their values.&lt;/p&gt;

&lt;h3&gt;
  
  
  The get_env function
&lt;/h3&gt;

&lt;p&gt;This function serves as a central piece in retrieving environment variables. It handles the logic to fetch variables from either a local .env file or AWS Secrets Manager. It gives precedence to remote values when available, and falls back to local values or default values if necessary.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default_value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&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;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;local_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default_value&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;remote_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;remote_environment_variable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;remote_value&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;remote_value&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;local_value&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;get_env&lt;/code&gt; function is responsible for retrieving the environment variable from either the local &lt;code&gt;.env&lt;/code&gt; file or AWS Secrets Manager.&lt;/p&gt;

&lt;p&gt;Within the function, it first attempts to retrieve the value from the local environment using &lt;code&gt;os.getenv(key, default_value)&lt;/code&gt;. The &lt;code&gt;os.getenv()&lt;/code&gt; function retrieves the value of the environment variable with the provided &lt;code&gt;key&lt;/code&gt;. The retrieved value, whether from the environment or the default value, is then converted to a string using the &lt;code&gt;str()&lt;/code&gt; function and stored in the local_value variable.&lt;/p&gt;

&lt;p&gt;Next, the function calls the &lt;code&gt;remote_environment_variable(key)&lt;/code&gt; function, which retrieves the value from AWS Secrets Manager. The result is stored in the &lt;code&gt;remote_value&lt;/code&gt; variable, also converted to a string representation.&lt;/p&gt;

&lt;p&gt;Finally, the function returns the &lt;code&gt;remote_value&lt;/code&gt; if it exists (i.e., is not an empty string) or falls back to the &lt;code&gt;local_value&lt;/code&gt; if the remote value is not available. This ensures that the function gives precedence to the remote value when both sources exist.&lt;/p&gt;

&lt;p&gt;In summary, the &lt;code&gt;get_env&lt;/code&gt; function provides a unified approach to retrieve environment variables, combining values from a local &lt;code&gt;.env&lt;/code&gt; file and AWS Secrets Manager. It prioritizes remote values when available, offering flexibility and consistency in handling environment variable retrieval.&lt;/p&gt;

&lt;h3&gt;
  
  
  The remote_environment_variable function
&lt;/h3&gt;

&lt;p&gt;This function is responsible for retrieving environment variables from AWS Secrets Manager. It uses the &lt;code&gt;AWS_SECRETS_MANAGER_SECRET_ID&lt;/code&gt; environment variable to identify the secret in AWS Secrets Manager and fetches the corresponding value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;remote_environment_variable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&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;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;secret_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"AWS_SECRETS_MANAGER_SECRET_ID"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;secret_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;aws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;secrets_manager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_secret_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SecretId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;secret_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ClientError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;NoCredentialsError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ParamValidationError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NoCredentialsError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ParamValidationError&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
            &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"AWS Secrets Manager: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'Error'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s"&gt;'Code'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; to secret"&lt;/span&gt;
            &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;secret_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="s"&gt;"SecretString"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;secret_dictionary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"SecretString"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;secret_dictionary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b64decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"SecretBinary"&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;secret_dictionary&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;remote_environment_variable&lt;/code&gt; function retrieves the value of an environment variable from AWS Secrets Manager. It takes one parameter, key, which represents the name of the environment variable to retrieve.&lt;/p&gt;

&lt;p&gt;First, the function retrieves the value of the &lt;code&gt;AWS_SECRETS_MANAGER_SECRET_ID&lt;/code&gt; environment variable using &lt;code&gt;os.getenv()&lt;/code&gt;. This value represents the ID of the secret in AWS Secrets Manager that contains all the desired environment variables stored as a JSON.&lt;/p&gt;

&lt;p&gt;If the &lt;code&gt;secret_id&lt;/code&gt; is not found or empty, indicating that the required environment variable is not available, the function returns an empty string.&lt;/p&gt;

&lt;p&gt;Next, the function attempts to fetch the secret value using the &lt;code&gt;aws.secrets_manager.get_secret_value()&lt;/code&gt; method, passing the &lt;code&gt;SecretId&lt;/code&gt; parameter with the retrieved &lt;code&gt;secret_id&lt;/code&gt;. Any potential exceptions, such as &lt;code&gt;ClientError&lt;/code&gt;, &lt;code&gt;NoCredentialsError&lt;/code&gt;, or &lt;code&gt;ParamValidationError&lt;/code&gt;, are caught and handled within the &lt;code&gt;except&lt;/code&gt; block.&lt;/p&gt;

&lt;p&gt;If the retrieval is successful, the function checks if the response contains a “SecretString” key. If present, it assumes the secret value is in string format and parses it using &lt;code&gt;json.loads()&lt;/code&gt;, storing the resulting dictionary in the &lt;code&gt;secret_dictionary&lt;/code&gt; variable. Otherwise, if the response contains a “SecretBinary” key, it assumes the secret value is in base64-encoded binary format and decodes it using &lt;code&gt;b64decode()&lt;/code&gt; before parsing it as a dictionary.&lt;/p&gt;

&lt;p&gt;Finally, the function attempts to retrieve the value associated with the provided &lt;code&gt;key&lt;/code&gt; from the &lt;code&gt;secret_dictionary&lt;/code&gt; using the &lt;code&gt;get()&lt;/code&gt; method. If the &lt;code&gt;key&lt;/code&gt; is found in the dictionary, the corresponding value is returned. If not found, &lt;code&gt;None&lt;/code&gt; is returned.&lt;/p&gt;

&lt;p&gt;In summary, the &lt;code&gt;remote_environment_variable&lt;/code&gt; function provides a way to retrieve environment variables from AWS Secrets Manager by utilizing the &lt;code&gt;AWS_SECRETS_MANAGER_SECRET_ID&lt;/code&gt; environment variable to identify the secret. It handles potential errors and exceptions during the retrieval process, ensuring robustness and reliable access to sensitive configuration values.&lt;/p&gt;

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

&lt;p&gt;This function demonstrates the usage of the env function in different scenarios.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;example_module&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;example_function&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="c1"&gt;# Example 1
&lt;/span&gt;    &lt;span class="n"&gt;database_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'DATABASE_URL'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;"The database URL is: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;database_url&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Example 2
&lt;/span&gt;    &lt;span class="n"&gt;api_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'API_KEY'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default_value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'DEFAULT_API_KEY'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;"The API key is: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Example 3
&lt;/span&gt;    &lt;span class="n"&gt;debug_mode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'DEBUG_MODE'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;debug_mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Debug mode is enabled."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Debug mode is disabled."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the first example it's possible to see a basic environment variable retrieval, it retrieves the value of the 'DATABASE_URL' environment variable and prints it. In the second example, retrieves the value of the 'API_KEY' environment variable with a default value and prints it. The third and last example handles boolean environment variables, it retrieves the value of the 'DEBUG_MODE' environment variable as a boolean and prints the debug mode status accordingly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Final thoughts
&lt;/h3&gt;

&lt;p&gt;Using this approach combined with the appropriated AWS EC2 ↔ AWS IAM configuration, it’s possible to centralize all environment variables into AWS Secrets Manager, eliminating the need to deal with an .env file during the deployment.&lt;/p&gt;

&lt;p&gt;Therefore, this solution presents two upsides to the application lifecycle; 1) simplification of the deployment due to the elimination of the .env file outside the local environment; 2) better security since you can establish IAM access polices in a way that just specific members of the team can add and modify the Secrets Manager entries.&lt;/p&gt;




&lt;p&gt;I'm Jack Miras, a Brazilian engineer who works mostly with infrastructure and backend development, for more of my stuff &lt;a href="https://dev.to/jackmiras"&gt;click here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

</description>
      <category>python</category>
      <category>env</category>
      <category>aws</category>
      <category>secretsmanager</category>
    </item>
    <item>
      <title>Python – A guide to AWS integration</title>
      <dc:creator>Jack Miras</dc:creator>
      <pubDate>Thu, 18 May 2023 14:12:37 +0000</pubDate>
      <link>https://dev.to/jackmiras/python-a-guide-to-aws-integration-513h</link>
      <guid>https://dev.to/jackmiras/python-a-guide-to-aws-integration-513h</guid>
      <description>&lt;p&gt;When working with the Amazon Web Services (AWS) platform, it's essential to understand how to interact with various services using the AWS SDK for Python (Boto3). In this guide, we'll explore three key components: Why to keep this code in an isolated module, AWS Session, S3 Client, and Secrets Manager Client. We'll discuss their functionalities and demonstrate how to use them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Content
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Keep the code in an isolated module&lt;/li&gt;
&lt;li&gt;AWS Session&lt;/li&gt;
&lt;li&gt;S3 Client&lt;/li&gt;
&lt;li&gt;Secrets Manager Client&lt;/li&gt;
&lt;li&gt;Final thoughts&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Keep the code in an isolated module
&lt;/h3&gt;

&lt;p&gt;When working with AWS services and Boto3, it's typically beneficial to keep the code in an isolated Python module. Here are some advantages of adopting this practice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Modularity:&lt;/strong&gt; Isolating the AWS-related code into a separate module promotes modularity and separation of concerns. It allows you to organize your codebase better and makes it easier to maintain and understand.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reusability:&lt;/strong&gt; By keeping the code in a dedicated module, you can reuse it across multiple projects or components within a larger application. This saves time and effort by avoiding code duplication.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Encapsulation:&lt;/strong&gt; Isolating the AWS code into a module provides encapsulation, ensuring that the AWS-related configurations and credentials are kept separate from the rest of the application code. This helps maintain a clean and secure codebase.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Testability:&lt;/strong&gt; An isolated module can be easily unit tested to verify its functionality independently of the rest of the application. This promotes better testing practices and improves overall code quality.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Scalability&lt;/strong&gt;: When your application grows and requires interaction with more AWS services, having an isolated module allows you to easily extend and add new functionality without affecting other parts of the codebase.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By following the practice of isolating AWS-related code into an independent module, you can reap these benefits and create more robust and maintainable applications on the AWS platform.&lt;/p&gt;

&lt;h3&gt;
  
  
  AWS Session
&lt;/h3&gt;

&lt;p&gt;The AWS Session is a crucial element that manages the state and configuration for interacting with AWS services. It encapsulates information such as credentials, regions, and profiles. To create an AWS Session using Boto3, we start by defining the session arguments, which include the region name, AWS access key ID, and AWS secret access key. These values can be retrieved from environment variables for security and flexibility. Then, we create the session using the provided arguments. Here's an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;boto3&lt;/span&gt;

&lt;span class="s"&gt;"""
---------------------------------------------------------------------------
AWS session
--------------------------------------------------------------------------

Client session that manages state about a particular configuration/account.
Sessions typically store credentials, AWS regions, and other configurations
related to a given profile.

"""&lt;/span&gt;

&lt;span class="n"&gt;session_args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="n"&gt;region_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"AWS_DEFAULT_REGION"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;aws_access_key_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"AWS_ACCESS_KEY_ID"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;aws_secret_access_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"AWS_SECRET_ACCESS_KEY"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;region_name&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;aws_access_key_id&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;aws_secret_access_key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;session_args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s"&gt;"region_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;region_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"aws_access_key_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;aws_access_key_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"aws_secret_access_key"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;aws_secret_access_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Session&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;session_args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By establishing an AWS Session, we ensure that subsequent interactions with AWS services use the provided credentials and configurations.&lt;/p&gt;

&lt;h3&gt;
  
  
  S3 Client
&lt;/h3&gt;

&lt;p&gt;The S3 Client is an essential component for working with Amazon Simple Storage Service (S3), which is a scalable object storage service offered by AWS. The S3 Client allows you to perform operations such as creating buckets, uploading files, listing objects, and more. To create an S3 Client, we can utilize the AWS Session we established earlier. Here's an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="s"&gt;"""
---------------------------------------------------------------------------
S3 Client
--------------------------------------------------------------------------

Amazon Simple Storage Service (Amazon S3) is an object storage service.

"""&lt;/span&gt;

&lt;span class="n"&gt;s3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"s3"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, you can use the &lt;code&gt;s3&lt;/code&gt; object to interact with your S3 resources and perform various operations as needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Secrets Manager Client
&lt;/h3&gt;

&lt;p&gt;AWS Secrets Manager is a service that helps you securely store and manage secrets such as database credentials, API keys, and other sensitive information. To work with Secrets Manager, we create a Secrets Manager Client using the AWS Session. This client allows us to retrieve and manage secrets throughout their lifecycles. Here's an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="s"&gt;"""
---------------------------------------------------------------------------
Secrets Manager Client
--------------------------------------------------------------------------


AWS Secrets Manager is service to, retrieve, and rotate database credentials,
API keys, and other secrets throughout their lifecycles.

"""&lt;/span&gt;

&lt;span class="n"&gt;secrets_manager&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"secretsmanager"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the &lt;code&gt;secrets_manager&lt;/code&gt; object, you can call various methods to retrieve secrets, create new secrets, update existing secrets, and more, depending on your requirements.&lt;/p&gt;

&lt;h3&gt;
  
  
  Final thoughts
&lt;/h3&gt;

&lt;p&gt;Understanding the AWS Session, S3 Client, and Secrets Manager Client is essential for building powerful and secure applications on the AWS platform. In this guide, we explored the functionalities of these components and demonstrated how to create them using Boto3. By leveraging these tools, you can effectively interact with AWS services, manage object storage with S3, and securely handle secrets using Secrets Manager.&lt;/p&gt;

&lt;p&gt;By harnessing the power of Boto3 and these AWS components, you can unlock the full potential of AWS services within your applications. Experiment with the provided code examples and explore the comprehensive Boto3 &lt;a href="https://boto3.amazonaws.com/v1/documentation/api/latest/index.html"&gt;documentation&lt;/a&gt; to dive deeper into the capabilities of these components and build robust AWS integrations with ease.&lt;/p&gt;




&lt;p&gt;I'm Jack Miras, a Brazilian engineer who works mostly with infrastructure and backend development, for more of my stuff &lt;a href="https://dev.to/jackmiras"&gt;click here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

</description>
      <category>python</category>
      <category>aws</category>
      <category>s3</category>
      <category>secretsmanager</category>
    </item>
    <item>
      <title>Python – Dynamically accessing object properties</title>
      <dc:creator>Jack Miras</dc:creator>
      <pubDate>Thu, 04 May 2023 04:11:09 +0000</pubDate>
      <link>https://dev.to/jackmiras/python-dynamically-accessing-object-properties-4056</link>
      <guid>https://dev.to/jackmiras/python-dynamically-accessing-object-properties-4056</guid>
      <description>&lt;p&gt;After coding Python for quite some time, today I needed to do something that should be pretty straightforward, but it took almost half an hour to figure it out, and the result wasn’t as expected.&lt;/p&gt;

&lt;h3&gt;
  
  
  Content
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;A simple problem&lt;/li&gt;
&lt;li&gt;What about production?&lt;/li&gt;
&lt;li&gt;Light at the end of the tunnel&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  A simple problem
&lt;/h3&gt;

&lt;p&gt;The problem presented itself when it was necessary to dynamically set a log level to a database connection based on an environment variable. As ORM, the project uses &lt;a href="http://docs.peewee-orm.com/en/latest/index.html"&gt;peewee&lt;/a&gt; which allows us to leverage Python’s standard logging lib to intercept a peewee log stream and do some manipulation such as changing the log level of the stream.&lt;/p&gt;

&lt;p&gt;According to the peewee’s &lt;a href="http://docs.peewee-orm.com/en/latest/peewee/database.html#logging-queries"&gt;doc&lt;/a&gt;, when in need to print all queries to the stderr, we just need to implement the following.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;logging&lt;/span&gt;

&lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getLogger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'peewee'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StreamHandler&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setLevel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DEBUG&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What about production?
&lt;/h3&gt;

&lt;p&gt;Once I read the code I thought “When deploying this to production another log level, such as ERROR, would be more appropriated to avoid showing unnecessary information from the database”.&lt;/p&gt;

&lt;p&gt;It’s important to carefully set up your logs to keep the application security risks to a minimum, since a log level with too much information can expose the database’s structure and sensitive data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Light at the end of the tunnel
&lt;/h3&gt;

&lt;p&gt;The approach chosen to solve this was to add an environment variable to the .env file called DB_LOG_LEVEL, that way the application could vary between DEBUG and ERROR levels of log based on the environment.&lt;/p&gt;

&lt;p&gt;Next, we need a way to apply some &lt;a href="https://stackoverflow.com/questions/514644/what-exactly-is-metaprogramming#514697"&gt;metaprogramming&lt;/a&gt; to dynamically call logging.DEBUG, since the log level the application is taking as the truth comes from env("DB_LOG_LEVEL").&lt;/p&gt;

&lt;p&gt;For that, we can use the built-in &lt;a href="https://docs.python.org/3/library/functions.html#getattr"&gt;getattr(…)&lt;/a&gt; function, that would return the value of the named attribute of an object, where the name must be a string. With knowledge of this function, let's see how our code would look like now.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;logging&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;getenv&lt;/span&gt;

&lt;span class="n"&gt;level&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DB_LOG_LEVEL"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"DEBUG"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getLogger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"peewee"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StreamHandler&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setLevel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I also added a validation that checks if the value returned by the &lt;code&gt;getenv(...)&lt;/code&gt; function matches the &lt;a href="https://github.com/python/cpython/blob/3.11/Lib/logging/__init__.py#L92-L99"&gt;log levels present in the logging library&lt;/a&gt;, which presents the following implementation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;logging&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;getenv&lt;/span&gt;

&lt;span class="s"&gt;"""
---------------------------------------------------------------------------
 Database logging
--------------------------------------------------------------------------

Database logging will define when and how log info will be shown while
interacting with the database. Accepted log levels are CRITICAL, ERROR,
WARNING, INFO, DEBUG and NOTSET.
"""&lt;/span&gt;


&lt;span class="n"&gt;LOG_LEVELS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s"&gt;"CRITICAL"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"FATAL"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"ERROR"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"WARNING"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"WARN"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"INFO"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"DEBUG"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"NOTSET"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;LOG_LEVEL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DB_LOG_LEVEL"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"DEBUG"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;LOG_LEVEL&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;LOG_LEVELS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;"DatabaseLogError: Log level '&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;LOG_LEVEL&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;' not defined"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getLogger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"peewee"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StreamHandler&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setLevel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;LOG_LEVEL&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DEBUG&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using metaprogramming to solve this problem, allows us to dynamically access a property of the object &lt;code&gt;logging&lt;/code&gt; to pass a valid log level into the &lt;code&gt;logger.setLevel(...)&lt;/code&gt; function.&lt;/p&gt;




&lt;p&gt;I'm Jack Miras, a Brazilian engineer who works mostly with infrastructure and backend development, for more of my stuff &lt;a href="https://dev.to/jackmiras"&gt;click here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

</description>
      <category>python</category>
      <category>logging</category>
      <category>database</category>
      <category>pewee</category>
    </item>
    <item>
      <title>Laravel: Delete Actions Simplified</title>
      <dc:creator>Jack Miras</dc:creator>
      <pubDate>Wed, 13 Jul 2022 00:52:51 +0000</pubDate>
      <link>https://dev.to/jackmiras/laravel-delete-actions-simplified-4h8b</link>
      <guid>https://dev.to/jackmiras/laravel-delete-actions-simplified-4h8b</guid>
      <description>&lt;p&gt;In my last &lt;a href="https://dev.to/jackmiras/laravel-update-actions-simplified-1djp"&gt;publishing&lt;/a&gt;, I've mentioned controller operations that are frequently duplicated and how we could leverage what we've learned so far to make those operations simpler to use. Now, I would like to discuss another controller operation that frequently gets duplicated as well, and that is the delete operation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Content
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Conventional way&lt;/li&gt;
&lt;li&gt;Shortening it&lt;/li&gt;
&lt;li&gt;The deleteOrFail function&lt;/li&gt;
&lt;li&gt;
Abstracting it

&lt;ul&gt;
&lt;li&gt;Trait abstraction&lt;/li&gt;
&lt;li&gt;The model function&lt;/li&gt;
&lt;li&gt;The deleteOrThrow function&lt;/li&gt;
&lt;li&gt;Custom exception&lt;/li&gt;
&lt;li&gt;Using the abstraction&lt;/li&gt;
&lt;li&gt;Implementing it&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Conventional way
&lt;/h3&gt;

&lt;p&gt;Before we jump into the simplification, let’s take a look at how a delete operation looks like when conventionally implemented.&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\Controllers&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;App\Models\User&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;Illuminate\Http\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;UsersController&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Controller&lt;/span&gt;
&lt;span class="p"&gt;{&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;destroy&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;Response&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&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="n"&gt;id&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;$user&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="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="s2"&gt;"User with id &lt;/span&gt;&lt;span class="si"&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="n"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; not found"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;HTTP_NOT_FOUND&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;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;false&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="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="s2"&gt;"Couldn't delete the user with id &lt;/span&gt;&lt;span class="si"&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="n"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;HTTP_BAD_REQUEST&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="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s2"&gt;"id"&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"deleted"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;HTTP_OK&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;On the first line, we are querying a user by its ID and storing the result in the &lt;code&gt;$user&lt;/code&gt; object.&lt;/p&gt;

&lt;p&gt;Then, at the first conditional, we check if the &lt;code&gt;$user&lt;/code&gt; is null; if it is, it means that no record with the given ID got found, and an error message with status 404 will be returned.&lt;/p&gt;

&lt;p&gt;Thereafter, we have a second conditional where we call &lt;code&gt;$user-&amp;gt;delete()&lt;/code&gt; this function returns true or false to let us know if the data got successfully deleted. In the event it returns false, an error message with status 400 will be returned.&lt;/p&gt;

&lt;p&gt;Finally, if the user got correctly deleted, we render a response with the user's &lt;code&gt;id&lt;/code&gt; and a property &lt;code&gt;deleted&lt;/code&gt; with the value &lt;code&gt;true&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Shortening it
&lt;/h3&gt;

&lt;p&gt;Why not use the &lt;code&gt;findOrFail()&lt;/code&gt; helper function to shorten our code? When using this approach, it would remove at least five lines from the destroy action of our controller, as shown in the code example down 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="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Http\Controllers&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;App\Models\User&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;Illuminate\Http\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;UsersController&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Controller&lt;/span&gt;
&lt;span class="p"&gt;{&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;destroy&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;Response&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;findOrFail&lt;/span&gt;&lt;span class="p"&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="n"&gt;id&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;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;false&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="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="s2"&gt;"Couldn't delete the user with id &lt;/span&gt;&lt;span class="si"&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="n"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;HTTP_BAD_REQUEST&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="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s2"&gt;"id"&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"deleted"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;HTTP_OK&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;On the first line, we are querying a user by its ID using the &lt;code&gt;findOrFail()&lt;/code&gt; function. This function has a special behavior where an exception gets thrown in case the data for the given ID doesn't get found.&lt;/p&gt;

&lt;p&gt;To make the most of this change, we need to know how to &lt;a href="https://dev.to/jackmiras/laravels-exceptions-part-3-findorfail-exception-automated-4kci"&gt;automate the handling of the exception&lt;/a&gt; thrown by the &lt;code&gt;findOrFail()&lt;/code&gt;. Otherwise, it would be necessary to use a try/catch block, and the number of lines would be just about the same.&lt;/p&gt;

&lt;p&gt;As in the previous example, we have a conditional where we are calling &lt;code&gt;$user-&amp;gt;delete()&lt;/code&gt; into the user that we want to delete. In the event it returns false, an error message with status 400 will be returned.&lt;/p&gt;

&lt;p&gt;Same as before, if the user was deleted, we render its &lt;code&gt;id&lt;/code&gt; and the property &lt;code&gt;deleted&lt;/code&gt; with the value &lt;code&gt;true&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The deleteOrFail function
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;NOTE: This function will only be available if you are using Laravel on version 8.58.0 or newer.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now that we’ve seen two different ways of implementing the delete action on Laravel, let’s see how we can implement this using the &lt;code&gt;deleteOrFail()&lt;/code&gt; function.&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\Controllers&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;App\Models\User&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;Illuminate\Http\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;Users&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Controller&lt;/span&gt;
&lt;span class="p"&gt;{&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;destroy&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;Response&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;findOrFail&lt;/span&gt;&lt;span class="p"&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="n"&gt;id&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;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;deleteOrFail&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;false&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="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="s2"&gt;"Couldn't delete the user with id &lt;/span&gt;&lt;span class="si"&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="n"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;HTTP_BAD_REQUEST&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="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s2"&gt;"id"&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"deleted"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;HTTP_OK&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;As before, we are querying a user by its ID using the &lt;code&gt;findOrFail()&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;Next, we have a second conditional where we call &lt;code&gt;$user-&amp;gt;deleteOrFail()&lt;/code&gt; this function returns true or false to let us know if the data got successfully deleted. In the event it returns false, an error message with status 400 will be returned.&lt;/p&gt;

&lt;p&gt;Once more, if the user got correctly deleted, we render its &lt;code&gt;id&lt;/code&gt; and &lt;code&gt;deleted&lt;/code&gt; as with the value &lt;code&gt;true&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;NOTE: Notice that the &lt;a href="https://github.com/laravel/framework/blob/9.x/src/Illuminate/Database/Eloquent/Model.php#L1304-L1320"&gt;deleteOrFail()&lt;/a&gt; check if the model itself exists, open a database connection, then a transaction and call the &lt;a href="https://github.com/laravel/framework/blob/9.x/src/Illuminate/Database/Eloquent/Model.php#L1263-L1302"&gt;delete()&lt;/a&gt; function, and the resultant usage is exactly the same as the one presented in the previous section.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is a very odd implementation in the framework, since most of the &lt;code&gt;*orFail()&lt;/code&gt; functions usually throw an exception. If that was the case, we could just automate the handling of the exception thrown by the &lt;code&gt;deleteOrFail()&lt;/code&gt; function the same way we did in the last post in my &lt;a href="https://dev.to/jackmiras/laravels-exceptions-part-3-findorfail-exception-automated-4kci"&gt;series about exceptions&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If we had a standard &lt;code&gt;*orFail()&lt;/code&gt; function, this function would be the simplest way of implementing a destroy action in a controller, completely removing the need for the approach that will be explained in the next section.&lt;/p&gt;

&lt;h3&gt;
  
  
  Abstracting it
&lt;/h3&gt;

&lt;p&gt;Let’s see how we can abstract this implementation in such a way that we get high reusability with simple usage out of this abstraction.&lt;/p&gt;

&lt;p&gt;Since this abstraction interacts with models, I wanted to avoid using inheritance because it would be a coupling too high for an abstraction as simple as this one.&lt;/p&gt;

&lt;p&gt;Furthermore, I want to leave the inheritance in the models open for usage, whether by a team member's decision or by some specific use case.&lt;/p&gt;

&lt;p&gt;For that reason, I’ve chosen to implement the abstraction as a Trait. Differently from C++, where we can use multiple inheritance, in PHP, a Trait is the mechanism to reduce limitations around single inheritance.&lt;/p&gt;

&lt;p&gt;Besides that, I have a personal rule where I use Traits only when an implementation gets highly reused, since a good portion of my controllers end up having a destroy action. In my context, this is something highly reused.&lt;/p&gt;

&lt;h4&gt;
  
  
  Trait abstraction
&lt;/h4&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\Helpers&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\Database\Eloquent\Model&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;App\Exceptions\ModelDeletionException&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;trait&lt;/span&gt; &lt;span class="nc"&gt;DeleteOrThrow&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/**
     * Instantiate a new model instance from the model implementing this trait.
     *
     * @return Model
     */&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;Model&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;get_class&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="cd"&gt;/**
     * Find a model by id, remove the model into the database,
     * otherwise it throws an exception.
     *
     * @param  int  $id
     * @return Model
     *
     * @throws \App\Exceptions\ModelDeletionException
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;deleteOrThrow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;Model&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;model&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;findOrFail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$id&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;$model&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;false&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="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ModelDeletionException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;get_class&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;$model&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;Our trait is composed of two functions: &lt;code&gt;model()&lt;/code&gt; which is responsible for returning an instance of the model implementing the trait, and &lt;code&gt;deleteOrThrow()&lt;/code&gt; which is responsible for deleting the model or throwing an exception in case delete fails.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Here we are simply implementing the behavior that I belive that would be the expected behavior for the new native &lt;code&gt;deleteOrFail()&lt;/code&gt; function, in fact, I used to call the &lt;code&gt;deleteOrThrow()&lt;/code&gt; function &lt;code&gt;deleteOrFail()&lt;/code&gt; but I had to rename it to not conflict with the &lt;code&gt;deleteOrFail()&lt;/code&gt; function implemented in Laravel 8.58.0.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h5&gt;
  
  
  The model function
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cd"&gt;/**
 * Instantiate the model implementing this trait by the model's class name.
 *
 * @return Model
 */&lt;/span&gt;
&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;Model&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;get_class&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;As mentioned, this function is responsible for returning an instance of the model implementing the trait, and since PHP allows us to use meta-programming to instantiate classes, let's take advantage of that and instantiate the model by its class name.&lt;/p&gt;

&lt;p&gt;In this function, we have a single line with a return statement that instantiates a new object out of the &lt;code&gt;get_class()&lt;/code&gt; function. To fully understand how this function works, let's assume that this trait was implemented by the User model. When evaluating the result of the function, we would get the string &lt;code&gt;"App\Models\User"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;When evaluated by the interpreter, this line would be the equivalent of &lt;code&gt;return new ("App\Models\User");&lt;/code&gt;, but the &lt;code&gt;get_class()&lt;/code&gt; gives us the dynamism of getting the right class name for each model implementing the trait.&lt;/p&gt;

&lt;h5&gt;
  
  
  The deleteOrThrow function
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cd"&gt;/**
 * Find a model by id, remove the model into the database,
 * otherwise it throws an exception.
 *
 * @param  int  $id
 * @return Model
 *
 * @throws \App\Exceptions\ModelDeletionException
 */&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;deleteOrThrow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;Model&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;model&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;findOrFail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$id&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;$model&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;false&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="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ModelDeletionException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;get_class&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;$model&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;In the first line, the &lt;code&gt;self::&lt;/code&gt; call indicates that we want to interact with the trait itself, and then we are chaining the &lt;code&gt;model()&lt;/code&gt; function to it, which means we are calling the function previously defined.&lt;/p&gt;

&lt;p&gt;Subsequently, we have a conditional where we are calling &lt;code&gt;$user-&amp;gt;delete()&lt;/code&gt;, in case the function returns false, a custom exception gets thrown.&lt;/p&gt;

&lt;p&gt;Finally, after a successful delete, we return the deleted model.&lt;/p&gt;

&lt;h4&gt;
  
  
  Custom exception
&lt;/h4&gt;

&lt;p&gt;Here we are using the same technique explained in the &lt;a href="https://dev.to/jackmiras/laravels-exceptions-part-2-custom-exceptions-1367"&gt;Laravel custom exceptions&lt;/a&gt; post. If you didn’t read the post yet, take a moment to read it, so you can make sense out of this section.&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\Exceptions&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\Str&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\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;ModelDeletionException&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;ApplicationException&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$model&lt;/span&gt;&lt;span class="p"&gt;;&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;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$id&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;$model&lt;/span&gt;&lt;span class="p"&gt;)&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="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$id&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="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Str&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;afterLast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&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;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;HTTP_BAD_REQUEST&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&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;help&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="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;trans&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'exception.model_not_deleted.help'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&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;error&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="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;trans&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'exception.model_not_deleted.error'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="s1"&gt;'id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'model'&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;model&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;At the class definition, we are extending the &lt;code&gt;ApplicationException&lt;/code&gt; which is an abstract class used to enforce the implementation of the &lt;code&gt;status()&lt;/code&gt;, &lt;code&gt;help()&lt;/code&gt; and &lt;code&gt;error()&lt;/code&gt; functions, and guaranteeing that Laravel will be able to handle this exception automatically.&lt;/p&gt;

&lt;p&gt;Following the class definition, we have the constructor, where property promotion is being used to make the code cleaner. As parameters, we have &lt;code&gt;$id&lt;/code&gt;, which contains the ID of the record we want to query from the database at our Trait, and &lt;code&gt;$model&lt;/code&gt; where the full class name of the model can be found.&lt;/p&gt;

&lt;p&gt;Inside the constructor, we are extracting the model name out of the full class name; the full name would be something like &lt;code&gt;App\Models\User&lt;/code&gt;, and we want just the User part. This is getting done, so we can automate the error message into something that makes sense to the person interacting with our API in case it’s not possible to find the record for a given ID.&lt;/p&gt;

&lt;p&gt;Next, we have the implementation of the &lt;code&gt;status()&lt;/code&gt; function, where we are returning the 400 HTTP status.&lt;/p&gt;

&lt;p&gt;Thereafter, we have the &lt;code&gt;help()&lt;/code&gt; function, where we return a translated string that indicates a possible solution to the error. In case you are wondering, the translated string would be evaluated to &lt;code&gt;Check your deleting parameter and try again&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Finally, we have the &lt;code&gt;error()&lt;/code&gt; function, where the error that happened gets specified. As in the previous function, we are using a translated string, but differently from before, here we are using the &lt;a href="https://laravel.com/docs/9.x/localization#replacing-parameters-in-translation-strings"&gt;replace parameters&lt;/a&gt; feature from trans().&lt;/p&gt;

&lt;p&gt;This approach was chosen to give us a dynamic error message with context. Here, the translated string would be evaluated to something like &lt;code&gt;User with id 1 not deleted&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;With this structure, if the target model changes, the message emitted by the exception would change as well since the model name gets dynamically defined.&lt;/p&gt;

&lt;p&gt;As a secondary example, imagine that now, you are interacting with a Sale model; in this case, the message would automatically change to &lt;code&gt;Sale with id 2 not deleted&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Using the abstraction
&lt;/h4&gt;

&lt;p&gt;Now that our abstraction has been defined, and we have guaranteed that the error handling is in place, we need to use our DeleteOrThrow Trait in the models that we want to have this simplified delete behavior.&lt;/p&gt;

&lt;p&gt;To achieve that, we just have to put in our models the &lt;code&gt;use DeleteOrThrow&lt;/code&gt;; exactly like the other Traits that normally Laravel brings in the models, you can see it with more details in the code example down 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="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Models&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;App\Helpers\DeleteOrThrow&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\Database\Eloquent\Factories\HasFactory&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\Auth\User&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nc"&gt;Authenticatable&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\Notifications\Notifiable&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;Laravel\Sanctum\HasApiTokens&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;User&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Authenticatable&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;HasFactory&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;Notifiable&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;HasApiTokens&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;DeleteOrThrow&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="mf"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Implementing it
&lt;/h4&gt;

&lt;p&gt;As a final result, we end up with an API call that looks like &lt;code&gt;User::deleteOrThrow($id)&lt;/code&gt; leaving us with a destroy action in our controllers that has a single line of implementation, and it is highly reusable.&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\Controllers&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;App\Models\User&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;Illuminate\Http\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;Users&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Controller&lt;/span&gt;
&lt;span class="p"&gt;{&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;destroy&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;Response&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;deleteOrThrow&lt;/span&gt;&lt;span class="p"&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="n"&gt;id&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;Happy coding!&lt;/p&gt;

</description>
      <category>php</category>
      <category>laravel</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Laravel: Update Actions Simplified</title>
      <dc:creator>Jack Miras</dc:creator>
      <pubDate>Fri, 22 Apr 2022 12:05:30 +0000</pubDate>
      <link>https://dev.to/jackmiras/laravel-update-actions-simplified-1djp</link>
      <guid>https://dev.to/jackmiras/laravel-update-actions-simplified-1djp</guid>
      <description>&lt;p&gt;When building APIs, we often come across CRUD operations. Even though these operations are one of the first things we learn when we start working with the backend, some of them can have significantly less code.&lt;/p&gt;

&lt;p&gt;Besides that, this code frequently gets duplicated across controllers. Through my journey working with Laravel, I've noticed that this happens typically in update functions, and that's why I decided to share how to simplify this implementation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Content
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Conventional way&lt;/li&gt;
&lt;li&gt;Shortening it&lt;/li&gt;
&lt;li&gt;The updateOrFail function&lt;/li&gt;
&lt;li&gt;
Abstracting it

&lt;ul&gt;
&lt;li&gt;Trait abstraction&lt;/li&gt;
&lt;li&gt;The model function&lt;/li&gt;
&lt;li&gt;The updateOrThrow function&lt;/li&gt;
&lt;li&gt;Custom exception&lt;/li&gt;
&lt;li&gt;Using the abstraction&lt;/li&gt;
&lt;li&gt;Implementing it&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Conventional way
&lt;/h3&gt;

&lt;p&gt;Before we jump into the simplification, let’s take a look at how an update operation looks like when conventionally implemented.&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\Controllers&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;App\Models\User&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;Illuminate\Http\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;UsersController&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Controller&lt;/span&gt;
&lt;span class="p"&gt;{&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;update&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;Response&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&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="n"&gt;id&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;$user&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="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="s2"&gt;"User with id &lt;/span&gt;&lt;span class="si"&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="n"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; not found"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;HTTP_NOT_FOUND&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;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&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;all&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;false&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="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="s2"&gt;"Couldn't update the user with id &lt;/span&gt;&lt;span class="si"&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="n"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;HTTP_BAD_REQUEST&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="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&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;On the first line, we are querying a user by its ID and storing the result in the &lt;code&gt;$user&lt;/code&gt; object.&lt;/p&gt;

&lt;p&gt;Then, at the first conditional, we check if the &lt;code&gt;$user&lt;/code&gt; is null; if it is, it means that no record with the given ID got found, and an error message with status 404 will be returned.&lt;/p&gt;

&lt;p&gt;Thereafter, we have a second conditional where we call &lt;code&gt;$user-&amp;gt;update()&lt;/code&gt; with the data that we want to update. This function returns true or false to let us know if the data was successfully updated. In the event it returns false, an error message with status 400 will be returned.&lt;/p&gt;

&lt;p&gt;Finally, if the data is successfully updated, we render the updated user as a response.&lt;/p&gt;

&lt;h3&gt;
  
  
  Shortening it
&lt;/h3&gt;

&lt;p&gt;Why not use the &lt;code&gt;findOrFail()&lt;/code&gt; helper function to shorten our code? When using this approach, it would remove at least five lines from the update action of our controller, as shown in the code example down 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="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Http\Controllers&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;App\Models\User&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;Illuminate\Http\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;UsersController&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Controller&lt;/span&gt;
&lt;span class="p"&gt;{&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;update&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;Response&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;findOrFail&lt;/span&gt;&lt;span class="p"&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="n"&gt;id&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;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&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;all&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;false&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="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="s2"&gt;"Couldn't update the user with id &lt;/span&gt;&lt;span class="si"&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="n"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;HTTP_BAD_REQUEST&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="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&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;On the first line, we are querying a user by its ID using the &lt;code&gt;findOrFail()&lt;/code&gt; function. This function has a special behavior where an exception gets thrown in case the data for the given ID doesn't get found.&lt;/p&gt;

&lt;p&gt;To make the most out of this change, we need to know how to &lt;a href="https://dev.to/jackmiras/laravels-exceptions-part-3-findorfail-exception-automated-4kci"&gt;automate the handling of the exception&lt;/a&gt; thrown by the &lt;code&gt;findOrFail()&lt;/code&gt;. Otherwise, it would be necessary to use a try/catch block, and the number of lines would be mostly the same.&lt;/p&gt;

&lt;p&gt;As in the previous example, we have a conditional where we are calling &lt;code&gt;$user-&amp;gt;update()&lt;/code&gt; with the data that we want to update. In the event it returns false, an error message with status 400 will be sent.&lt;/p&gt;

&lt;p&gt;Finally, if the user was correctly updated, we render the updated user as a response.&lt;/p&gt;

&lt;h3&gt;
  
  
  The updateOrFail function
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;NOTE: This function will only be available if you are using Laravel on version 8.58.0 or newer.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now that we’ve seen two different ways of implementing the update action on Laravel, let’s see how we can implement this using the &lt;code&gt;updateOrFail()&lt;/code&gt; function.&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\Controllers&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;App\Models\User&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;Illuminate\Http\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;App\Exceptions\ModelUpdatingException&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;Users&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Controller&lt;/span&gt;
&lt;span class="p"&gt;{&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;update&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;Response&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;findOrFail&lt;/span&gt;&lt;span class="p"&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="n"&gt;id&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;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;updateOrFail&lt;/span&gt;&lt;span class="p"&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;all&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;false&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="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="s2"&gt;"Couldn't update the user with id &lt;/span&gt;&lt;span class="si"&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="n"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;HTTP_BAD_REQUEST&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="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&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;On the first line, we are querying a user by its ID using the &lt;code&gt;findOrFail()&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;Next, we have a second conditional where we call &lt;code&gt;$user-&amp;gt;updateOrFail()&lt;/code&gt; with the data that we want to update. This function returns true or false to let us know if the data was successfully updated. In the event it returns false, an error message with status 400 will be returned.&lt;/p&gt;

&lt;p&gt;And again, if the user was correctly updated, we render the updated user as a response.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;NOTE: Notice that the &lt;a href="https://github.com/laravel/framework/blob/9.x/src/Illuminate/Database/Eloquent/Model.php#L890-L906"&gt;updateOrFail()&lt;/a&gt; function doesn't have any significant difference from the &lt;a href="https://github.com/laravel/framework/blob/9.x/src/Illuminate/Database/Eloquent/Model.php#L874-L888"&gt;update()&lt;/a&gt; function, and the resultant usage is exactly the same as the one presented in the previous section.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is a very odd implementation in the framework, since most of the &lt;code&gt;*orFail()&lt;/code&gt; functions usually throw an exception. If that was the case, we could just automate the handling of the exception thrown by the &lt;code&gt;updateOrFail()&lt;/code&gt; function the same way we did in the last post in my &lt;a href="https://dev.to/jackmiras/laravels-exceptions-part-3-findorfail-exception-automated-4kci"&gt;series about exceptions&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If we had a standard &lt;code&gt;*orFail()&lt;/code&gt; function, this function would be the simplest way of implementing an update action in a controller, completely removing the need for the approach that will be explained in the next section.&lt;/p&gt;

&lt;h3&gt;
  
  
  Abstracting it
&lt;/h3&gt;

&lt;p&gt;Let’s see how we can abstract this implementation in such a way that we get high reusability with simple usage out of this abstraction.&lt;/p&gt;

&lt;p&gt;Since this abstraction interacts with models, I wanted to avoid using inheritance because it would be a coupling too high for an abstraction as simple as this one.&lt;/p&gt;

&lt;p&gt;Furthermore, I want to leave the inheritance in the models open for usage, whether by a team member's decision or by some specific use case.&lt;/p&gt;

&lt;p&gt;For that reason, I’ve chosen to implement the abstraction as a trait. Differently from C++, where we can use multiple inheritance, in PHP, a trait is the mechanism to reduce limitations around single inheritance.&lt;/p&gt;

&lt;p&gt;Besides that, I have a personal rule where I use traits only when an implementation gets highly reused. Since most of my controllers end up having an update action, in my context, this is something highly reused.&lt;/p&gt;

&lt;h4&gt;
  
  
  Trait abstraction
&lt;/h4&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\Helpers&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\Database\Eloquent\Model&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;App\Exceptions\ModelUpdatingException&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;trait&lt;/span&gt; &lt;span class="nc"&gt;UpdateOrThrow&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/**
     * Instantiate the model implementing this trait by the model's class name.
     *
     * @return Model
     */&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;Model&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;get_class&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="cd"&gt;/**
     * Find a model by id, fill the model with an array of attributes, update
     * the model into the database, otherwise it throws an exception.
     *
     * @param  int  $id
     * @param  array  $attributes
     * @return Model
     *
     * @throws \App\Exceptions\ModelUpdatingException
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;updateOrThrow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$attributes&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;Model&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;model&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;findOrFail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$id&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;fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$attributes&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;$model&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;false&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="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ModelUpdatingException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;get_class&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;$model&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;Our trait will be a compound of two functions: &lt;code&gt;model()&lt;/code&gt; which is responsible for returning an instance of the model implementing the trait, and &lt;code&gt;updateOrThrow()&lt;/code&gt; which is responsible for updating the model or throwing an exception in case the update fails.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Here we are simply implementing the behavior that I belive that would be the expected behavior for the new native &lt;code&gt;updateOrFail()&lt;/code&gt; function, in fact, I used to call the &lt;code&gt;updateOrThrow()&lt;/code&gt; function &lt;code&gt;updateOrFail()&lt;/code&gt; but I had to rename it to not conflict with the &lt;code&gt;updateOrFail()&lt;/code&gt; function implemented in Laravel 8.58.0.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h5&gt;
  
  
  The model function
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cd"&gt;/**
 * Instantiate the model implementing this trait by the model's class name.
 *
 * @return Model
 */&lt;/span&gt;
&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;Model&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;get_class&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;As mentioned, this function is responsible for returning an instance of the model implementing the trait, and since PHP allows us to use meta-programming to instantiate classes, let's take advantage of that and instantiate the model by its class name.&lt;/p&gt;

&lt;p&gt;In this function, we have a single line with a return statement that instantiates a new object out of the &lt;code&gt;get_class()&lt;/code&gt; function. To fully understand how this function works, let's assume that this trait was implemented by the User model. When evaluating the result of the function, we would get the string &lt;code&gt;"App\Models\User"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;When evaluated by the interpreter, this line would be the equivalent of &lt;code&gt;return new ("App\Models\User");&lt;/code&gt;, but the &lt;code&gt;get_class()&lt;/code&gt; gives us the dynamism of getting the right class name for each model implementing the trait.&lt;/p&gt;

&lt;h5&gt;
  
  
  The updateOrThrow function
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cd"&gt;/**
 * Find a model by id, fill the model with an array of attributes, update
 * the model into the database, otherwise it throws an exception.
 *
 * @param  int  $id
 * @param  array  $attributes
 * @return Model
 *
 * @throws \App\Exceptions\ModelUpdatingException
 */&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;updateOrThrow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$attributes&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;Model&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;model&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;findOrFail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$id&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;fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$attributes&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;$model&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;false&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="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ModelUpdatingException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;get_class&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;$model&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;In the first line, the &lt;code&gt;self::&lt;/code&gt; call indicates that we want to interact with the trait itself, and then we are chaining the &lt;code&gt;model()&lt;/code&gt; function to it, which means we are calling the function previously defined.&lt;/p&gt;

&lt;p&gt;Then we chain into the &lt;code&gt;model()&lt;/code&gt; function call the &lt;code&gt;findOrFail()&lt;/code&gt; function, passing the ID of the record we would like to retrieve from the database. Once the record gets found and a populated model gets returned, we chain the &lt;code&gt;fill()&lt;/code&gt; function call, passing the data that we want to update.&lt;/p&gt;

&lt;p&gt;Subsequently, we have a conditional where we call &lt;code&gt;$user-&amp;gt;update()&lt;/code&gt; this function returns true or false to let us know if the data got successfully updated. In case it returns false, a custom exception gets thrown.&lt;/p&gt;

&lt;p&gt;Finally, after a successful update, we returned the updated model.&lt;/p&gt;

&lt;h4&gt;
  
  
  Custom exception
&lt;/h4&gt;

&lt;p&gt;Here we are using the same technique explained in the &lt;a href="https://dev.to/jackmiras/laravels-exceptions-part-2-custom-exceptions-1367"&gt;Laravel custom exceptions&lt;/a&gt; post. If you didn’t read the post yet, take a moment to read it, so you can make sense out of this section.&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\Exceptions&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\Str&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\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;ModelUpdatingException&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;ApplicationException&lt;/span&gt;
&lt;span class="p"&gt;{&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;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$model&lt;/span&gt;&lt;span class="p"&gt;)&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="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Str&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;afterLast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&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;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;HTTP_BAD_REQUEST&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&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;help&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="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;trans&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'exception.model_not_updated.help'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&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;error&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="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;trans&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'exception.model_not_updated.error'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="s1"&gt;'id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'model'&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;model&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;At the class definition, we are extending the &lt;code&gt;ApplicationException&lt;/code&gt; which is an abstract class used to enforce the implementation of the &lt;code&gt;status()&lt;/code&gt;, &lt;code&gt;help()&lt;/code&gt; and &lt;code&gt;error()&lt;/code&gt; functions, and guaranteeing that Laravel will be able to handle this exception automatically.&lt;/p&gt;

&lt;p&gt;Following the class definition, we have the constructor, where property promotion is being used to make the code cleaner. As parameters, we have &lt;code&gt;$id&lt;/code&gt;, which contains the ID of the record we want to query from the database at our trait, and &lt;code&gt;$model&lt;/code&gt; where the full class name of the model can be found.&lt;/p&gt;

&lt;p&gt;Inside the constructor, we are extracting the model name out of the full class name; the full name would be something like &lt;code&gt;App\Models\User&lt;/code&gt;, and we want just the User part. This is getting done, so we can automate the error message into something that makes sense to the person interacting with our API in case it’s not possible to find the record for a given ID.&lt;/p&gt;

&lt;p&gt;Next, we have the implementation of the &lt;code&gt;status()&lt;/code&gt; function, where we are returning the 400 HTTP status.&lt;/p&gt;

&lt;p&gt;Thereafter, we have the &lt;code&gt;help()&lt;/code&gt; function, where we return a translated string that indicates a possible solution to the error. In case you are wondering, the translated string would be evaluated to &lt;code&gt;Check your update parameters and try again&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Finally, we have the &lt;code&gt;error()&lt;/code&gt; function, where the error that happened gets specified. As in the previous function, we are using a translated string, but differently from before, here we are using the &lt;a href="https://laravel.com/docs/8.x/localization#replacing-parameters-in-translation-strings"&gt;replace parameters&lt;/a&gt; feature from trans().&lt;/p&gt;

&lt;p&gt;This approach was chosen to give us a dynamic error message with context. Here, the translated string would be evaluated to something like &lt;code&gt;User with id 1 not updated&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;With this structure, if the target model changes, the message emitted by the exception would change as well since the model name gets dynamically defined.&lt;/p&gt;

&lt;p&gt;As a secondary example, imagine that now, you are interacting with a Sale model; in this case, the message would automatically change to &lt;code&gt;Sale with id 2 not updated&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Using the abstraction
&lt;/h4&gt;

&lt;p&gt;Now that our abstraction has been defined, and we have guaranteed that the error handling is in place, we need to use our UpdateOrThrow trait in the models that we want to have this simplified update behavior.&lt;/p&gt;

&lt;p&gt;To achieve that, we just have to put in our models the &lt;code&gt;use UpdateOrThrow&lt;/code&gt;; exactly like the other traits that normally Laravel brings in the models, you can see it with more details in the code example down 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="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Models&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;App\Helpers\UpdateOrThrow&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\Database\Eloquent\Factories\HasFactory&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\Auth\User&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nc"&gt;Authenticatable&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\Notifications\Notifiable&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;Laravel\Sanctum\HasApiTokens&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;User&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Authenticatable&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;HasFactory&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;Notifiable&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;HasApiTokens&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;UpdateOrThrow&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="mf"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Implementing it
&lt;/h4&gt;

&lt;p&gt;As a final result, we end up with an API call that looks like &lt;code&gt;User::updateOrThrow($id, $params)&lt;/code&gt; leaving us with an update action in our controllers that has a single line of implementation, and is highly reusable.&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\Controllers&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;App\Models\User&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;Illuminate\Http\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;Users&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Controller&lt;/span&gt;
&lt;span class="p"&gt;{&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;update&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;Response&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;updateOrThrow&lt;/span&gt;&lt;span class="p"&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="n"&gt;id&lt;/span&gt;&lt;span class="p"&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;all&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;Happy coding!&lt;/p&gt;

</description>
      <category>php</category>
      <category>laravel</category>
      <category>programm</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Laravel's exceptions: Part 3 – findOrFail exception automated</title>
      <dc:creator>Jack Miras</dc:creator>
      <pubDate>Fri, 18 Feb 2022 12:33:40 +0000</pubDate>
      <link>https://dev.to/jackmiras/laravels-exceptions-part-3-findorfail-exception-automated-4kci</link>
      <guid>https://dev.to/jackmiras/laravels-exceptions-part-3-findorfail-exception-automated-4kci</guid>
      <description>&lt;p&gt;When implementing something that requires querying the database to find a record by its ID, the first thing that comes to mind is the &lt;code&gt;find()&lt;/code&gt; function from &lt;a href="https://laravel.com/docs/9.x/eloquent"&gt;Eloquent&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Even though the function works, and you will be able to retrieve your data when it exists, a null object will be returned if the record is not found, and this null object usually brings unnecessary complexity.&lt;/p&gt;

&lt;p&gt;As you know, Laravel is a full-featured framework, but one of the features that blew my mind once I got the hang of it, was the exception handling of the framework. It’s not random that some of Laravel’s helpers throw exceptions instead of returning null objects, such as the &lt;code&gt;findOrFail()&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;These helpers that throw exceptions can be pretty handy when you learn how to automate the handling of their exceptions, making the code cleaner and shorter. But before we dive into those functions or Laravel’s exception handler, let’s take a look at ways that a find operation can be implemented.&lt;/p&gt;

&lt;h3&gt;
  
  
  Content
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
Ways to implement

&lt;ul&gt;
&lt;li&gt;The find function&lt;/li&gt;
&lt;li&gt;The findOrFail function&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Automating exceptions&lt;/li&gt;
&lt;li&gt;Final implementation&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Ways to implement
&lt;/h2&gt;

&lt;p&gt;In the following two sections, we will see the most conventional ways of implementing a find operation. You will notice that the number of lines between the implementations is the same; although they are entirely different implementations and there are no real advantages between them, the choice of the approach is just a matter of preference.&lt;/p&gt;

&lt;h3&gt;
  
  
  The find function
&lt;/h3&gt;

&lt;p&gt;Down below, we have a real use case where we are implementing a show action to the UsersController to find a user by its ID and render the record as a response to an endpoint.&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\Controllers&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;App\Models\User&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;Illuminate\Http\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;UsersController&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Controller&lt;/span&gt;
&lt;span class="p"&gt;{&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;show&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;Response&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&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="n"&gt;id&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;$user&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="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"User with id &lt;/span&gt;&lt;span class="si"&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="n"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; not found"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;HTTP_NOT_FOUND&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="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&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 query a user by its ID using the find function and store its result in an &lt;code&gt;$user&lt;/code&gt; object.&lt;/p&gt;

&lt;p&gt;Next, because the record of a given ID may not be found in the database, we are checking if the &lt;code&gt;$user&lt;/code&gt; is null; in case it is, we will return a message that would evaluate to &lt;code&gt;User with id 1 not found&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Finally, if the ID passed into the query got found, the user object would be present, and we could just return it as a response to the API call.&lt;/p&gt;

&lt;h3&gt;
  
  
  The findOrFail function
&lt;/h3&gt;

&lt;p&gt;With the same use case as before, let’s try a second approach and see how our code looks when using the &lt;code&gt;findOrFail()&lt;/code&gt; function without automating its exception handling.&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\Controllers&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;App\Models\User&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;Illuminate\Http\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\Database\Eloquent\ModelNotFoundException&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;UsersController&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Controller&lt;/span&gt;
&lt;span class="p"&gt;{&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;show&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;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;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;findOrFail&lt;/span&gt;&lt;span class="p"&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="n"&gt;id&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;ModelNotFoundException&lt;/span&gt; &lt;span class="nv"&gt;$exception&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="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"User with id &lt;/span&gt;&lt;span class="si"&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="n"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; not found"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;HTTP_NOT_FOUND&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="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&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;At the &lt;code&gt;try{}&lt;/code&gt; block we are querying the user by its ID; when found, we will place the data at the &lt;code&gt;$user&lt;/code&gt;, but unlike the previous approach, a ModelNotFoundException will be thrown in case the record doesn't exist.&lt;/p&gt;

&lt;p&gt;Thereafter, the &lt;code&gt;catch{}&lt;/code&gt; block gets used to intercept the exception thrown; once the exception gets intercepted, we build a response with a message that would be evaluated to &lt;code&gt;User with id 1 not found&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Then, if the given ID gets found, the &lt;code&gt;$user&lt;/code&gt; object would be present, and we would return it as a response to the endpoint.&lt;/p&gt;

&lt;h3&gt;
  
  
  Automating exceptions
&lt;/h3&gt;

&lt;p&gt;It’s important to notice that the approach about to be explained can be used to automate the handling of various Laravel exceptions. By automating these exceptions, you will have cleaner code and a more structured way of handling the exceptions.&lt;/p&gt;

&lt;p&gt;To automatically handle the exception thrown by the &lt;code&gt;findOrFail()&lt;/code&gt; function, we will have to override the &lt;code&gt;render()&lt;/code&gt; function in the &lt;strong&gt;app/Exceptions/Handler.php&lt;/strong&gt; class, as shown in the example down 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="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Exceptions&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;Throwable&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\Arr&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\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\Database\Eloquent\ModelNotFoundException&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\Exceptions\Handler&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nc"&gt;ExceptionHandler&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;Handler&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;ExceptionHandler&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/**
     * Render an exception into an HTTP response.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Throwable  $e
     * @return \Symfony\Component\HttpFoundation\Response
     *
     * @throws \Throwable
     */&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;render&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;Throwable&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;$e&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;ModelNotFoundException&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$replacement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="s1"&gt;'id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;collect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$e&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getIds&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;first&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                &lt;span class="s1"&gt;'model'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Arr&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;last&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;explode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'\\'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$e&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getModel&lt;/span&gt;&lt;span class="p"&gt;())),&lt;/span&gt;
            &lt;span class="p"&gt;];&lt;/span&gt;

            &lt;span class="nv"&gt;$error&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;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;trans&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'exception.model_not_found.help'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;trans&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'exception.model_not_found.error'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$replacement&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="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$error&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;toArray&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;HTTP_NOT_FOUND&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="k"&gt;parent&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;render&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;$e&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;We start by declaring a conditional that checks if the &lt;code&gt;$e&lt;/code&gt; being received in the &lt;code&gt;render()&lt;/code&gt; parameter is an instance of the ModelNotFoundException thrown by the &lt;code&gt;findOrFail()&lt;/code&gt; used in the previous examples.&lt;/p&gt;

&lt;p&gt;Then, we create a &lt;code&gt;$replacement&lt;/code&gt; array, an associative with the keys id and model, whose values are getting extracted from the intercepted exception. This replacement array gets used as a &lt;a href="https://laravel.com/docs/8.x/localization#replacing-parameters-in-translation-strings"&gt;replacement parameter&lt;/a&gt; in a &lt;code&gt;trans()&lt;/code&gt; function that gets called in the constructor of the error object.&lt;/p&gt;

&lt;p&gt;Subsequently, we are creating an &lt;code&gt;$error&lt;/code&gt; object. In case you don’t know what this &lt;em&gt;Error&lt;/em&gt; class is about, please take a moment to read the previous post in this series, where I discuss &lt;a href="https://dev.to/jackmiras/laravels-exceptions-part-2-custom-exceptions-1367"&gt;custom exceptions&lt;/a&gt;. The error class takes two mandatory parameters: &lt;code&gt;$help&lt;/code&gt; which shows a possible solution to the error, and &lt;code&gt;$error&lt;/code&gt; where the error that happened gets specified.&lt;/p&gt;

&lt;p&gt;Note that we are using named parameters and the &lt;code&gt;trans()&lt;/code&gt; helper to specify the messages we want to pass into the &lt;code&gt;$help&lt;/code&gt; and &lt;code&gt;$error&lt;/code&gt; parameters from the error object.&lt;/p&gt;

&lt;p&gt;Lastly, with the error object instantiated, we can build the response object to be rendered to the API call. To achieve that, we are using the &lt;code&gt;response()&lt;/code&gt; function passing &lt;code&gt;$error-&amp;gt;toArray()&lt;/code&gt; as the first parameter, and &lt;code&gt;Response::HTTP_BAD_REQUEST&lt;/code&gt; as the second one, which is the constant of the HTTP status 400.&lt;/p&gt;

&lt;h3&gt;
  
  
  Final implementation
&lt;/h3&gt;

&lt;p&gt;As a final result, we have a show action that can be implemented with one single line, without the need for checking for a null object nor  try/catch blocks to handle the exception getting thrown.&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\Controllers&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;App\Models\User&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;Illuminate\Http\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;UsersController&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Controller&lt;/span&gt;
&lt;span class="p"&gt;{&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;shows&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;Response&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;findOrFail&lt;/span&gt;&lt;span class="p"&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="n"&gt;id&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;Now our findOrFail exception automation is done.&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

</description>
      <category>php</category>
      <category>laravel</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Laravel's exceptions: Part 2 – Custom exceptions</title>
      <dc:creator>Jack Miras</dc:creator>
      <pubDate>Thu, 10 Feb 2022 02:00:33 +0000</pubDate>
      <link>https://dev.to/jackmiras/laravels-exceptions-part-2-custom-exceptions-1367</link>
      <guid>https://dev.to/jackmiras/laravels-exceptions-part-2-custom-exceptions-1367</guid>
      <description>&lt;p&gt;After working with Laravel for a while and learning about its way of handling exceptions, I found myself creating my own exceptions, either to simplify some if/else statements or to terminate function calls or even features.&lt;/p&gt;

&lt;p&gt;These custom exceptions are helpful, especially when combined with the &lt;a href="https://laravel.com/docs/8.x/helpers#method-throw-if"&gt;throw_if&lt;/a&gt; and &lt;a href="https://laravel.com/docs/8.x/helpers#method-throw-unless"&gt;throw_unless&lt;/a&gt; functions, which provide a cleaner way of throwing conditional exceptions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Content
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Understanding custom exception&lt;/li&gt;
&lt;li&gt;
Structuring custom exceptions

&lt;ul&gt;
&lt;li&gt;Making exceptions simple and extensible&lt;/li&gt;
&lt;li&gt;Standardizing errors&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Creating the JsonEncodeException&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Understanding custom exceptions
&lt;/h3&gt;

&lt;p&gt;Laravel can handle custom exceptions automatically when the exception is created in a certain way. First, the exception has to extend the Exception class, and then, in case you want to render something to the end user, you have to override the &lt;code&gt;render()&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;If you need to create an exception that will extend a class that isn’t the Exception class, Laravel won’t be able to automatically handle the exception, and as a result, you will have to use a try/catch block.&lt;/p&gt;

&lt;p&gt;Check the following code example to better understand how a custom exception can be defined.&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\Exceptions&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;Exception&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\Response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyCustomException&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="err"&gt;   &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;render&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;Response&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt;       &lt;/span&gt; &lt;span class="nv"&gt;$status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="err"&gt;       &lt;/span&gt; &lt;span class="nv"&gt;$error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Something is wrong"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="err"&gt;       &lt;/span&gt; &lt;span class="nv"&gt;$help&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Contact the sales team to verify"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="err"&gt;       &lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s2"&gt;"error"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"help"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$help&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nv"&gt;$status&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="err"&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;The result, from the exception above, would be a response with HTTP status 400 and a JSON in the following format:&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;   &lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Something is wrong"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;   &lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"help"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Contact the sales team to verify"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To test this example and validate the rendered JSON, you can use plain PHP to throw the exception just like this &lt;code&gt;throw new MyCustomException()&lt;/code&gt;;&lt;/p&gt;

&lt;h3&gt;
  
  
  Structuring custom exceptions
&lt;/h3&gt;

&lt;p&gt;Even though the creation of custom exceptions is pretty straightforward, it’s possible to design a more robust architecture around exceptions. The design that will be presented in this post has two premises.&lt;/p&gt;

&lt;p&gt; 1) Making exceptions simple and extensible.&lt;br&gt;
 2) Standardize the way error responses are shown.&lt;/p&gt;

&lt;p&gt;For them to be simpler and more extensible, we need to define a structure from which every custom exception can derive.&lt;/p&gt;

&lt;p&gt;As for standardizing them, it’s required to define how the error will be shown to the end user, and it is important to display your errors in a single, structured manner. Otherwise, front-end applications or other APIs integrating with yours won’t be able to trust your error responses, and these kinds of applications are just horrible to work with.&lt;/p&gt;
&lt;h4&gt;
  
  
  Making exceptions simple and extensible
&lt;/h4&gt;

&lt;p&gt;So, how can we implement custom exceptions in a way that we can enforce that every exception will comply with the appropriate status code, error, message, and other properties consistently on a basis that can be reused? For that, we can define an abstraction that all custom exceptions will implement, as the code below shows.&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\Exceptions&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;Exception&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;Illuminate\Http\Response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ApplicationException&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="k"&gt;abstract&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;status&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="k"&gt;abstract&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;help&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="err"&gt;   &lt;/span&gt; &lt;span class="k"&gt;abstract&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;error&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="err"&gt;   &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;render&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;Response&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt;       &lt;/span&gt; &lt;span class="nv"&gt;$error&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;Error&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;help&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;error&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="err"&gt;       &lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$error&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;toArray&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;status&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="err"&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;Here, an abstract class gets defined to enforce that every exception will implement a &lt;code&gt;status()&lt;/code&gt;, &lt;code&gt;help()&lt;/code&gt; and &lt;code&gt;error()&lt;/code&gt; functions.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;render()&lt;/code&gt; function that we are overriding from the &lt;code&gt;Exception&lt;/code&gt; class, we are using the result of the implementation of our help and error methods to create an error object.&lt;/p&gt;

&lt;p&gt;The error object is responsible for standardizing the errors in the application; it doesn’t matter whether the error was from an exception or a business rule validation; if it is an error, it will be encapsulated into the error object.&lt;/p&gt;

&lt;h4&gt;
  
  
  Standardizing errors
&lt;/h4&gt;

&lt;p&gt;To standardize errors, we will create the already mentioned and previously used error object. This object has two main characteristics.&lt;/p&gt;

&lt;p&gt;1) Define the data properties that will be shown when rendering the error.&lt;br&gt;
2) Be able to be automatically transformed into JSON by Laravel.&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\Exceptions&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;JsonSerializable&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\Contracts\Support\Jsonable&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\Contracts\Support\Arrayable&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;Error&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Arrayable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Jsonable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;JsonSerializable&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt;   &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;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$help&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="err"&gt;   &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;toArray&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt;       &lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="err"&gt;           &lt;/span&gt; &lt;span class="s1"&gt;'error'&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="err"&gt;           &lt;/span&gt; &lt;span class="s1"&gt;'help'&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;help&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="err"&gt;       &lt;/span&gt; &lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="err"&gt;   &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;jsonSerialize&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt;       &lt;/span&gt; &lt;span class="k"&gt;return&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;toArray&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="err"&gt;   &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;toJson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt;       &lt;/span&gt; &lt;span class="nv"&gt;$jsonEncoded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;json_encode&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;jsonSerialize&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nv"&gt;$options&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="err"&gt;       &lt;/span&gt; &lt;span class="nf"&gt;throw_unless&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$jsonEncoded&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;JsonEncodeException&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="err"&gt;       &lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$jsonEncoded&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="err"&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;Notice that the class declaration implements three interfaces; these interfaces are responsible for making the class capable of being converted into an array or a JSON.&lt;/p&gt;

&lt;p&gt;Following the class declaration, we have the constructor where property promotion is getting used to keep the code cleaner; as parameters, we have &lt;code&gt;$help&lt;/code&gt; which shows a possible solution to the error getting shown, and &lt;code&gt;$error&lt;/code&gt; where the error that happened gets specified.&lt;/p&gt;

&lt;p&gt;Next, we have the &lt;code&gt;toArray()&lt;/code&gt; function, where the error object gets returned as an array.&lt;/p&gt;

&lt;p&gt;Then we have the &lt;code&gt;jsonSerialize()&lt;/code&gt; function, where the error object also returns as an array. Here we are applying DRY and just calling the &lt;code&gt;toArray()&lt;/code&gt; inside the &lt;code&gt;jsonSerialize()&lt;/code&gt; function; since they return the same result, there is no reason for us to repeat ourselves.&lt;/p&gt;

&lt;p&gt;Finally, we have the &lt;code&gt;toJson()&lt;/code&gt; function, where our object gets converted into a JSON string. Notice that we start by calling the &lt;code&gt;json_encode()&lt;/code&gt;. To this function, we are passing as parameters the result from &lt;code&gt;jsonSerializer()&lt;/code&gt; previously implemented and the &lt;code&gt;$options&lt;/code&gt; from the function itself.&lt;/p&gt;

&lt;p&gt;As a result, we should have the &lt;code&gt;$jsonEncoded&lt;/code&gt; variable a JSON string matching the information present in our error object; however, in cases where &lt;code&gt;json_encode()&lt;/code&gt; can’t transform the array passed as a parameter into JSON, it will return a boolean false.&lt;/p&gt;

&lt;p&gt;For that reason, in the next line we’re using the &lt;code&gt;throw_unless()&lt;/code&gt; helper to throw an exception in case &lt;code&gt;$jsonEncoded&lt;/code&gt; is evaluated to false, and otherwise we return the JSON string in the subsequent line.&lt;br&gt;
Now we just need to define the &lt;code&gt;JsonEncodeException&lt;/code&gt; that we conditionally throw in the &lt;code&gt;toJson()&lt;/code&gt; function.&lt;/p&gt;
&lt;h3&gt;
  
  
  Creating the JsonEncodeException
&lt;/h3&gt;

&lt;p&gt;Considering that this exception is a custom exception written specially to handle the JSON conversion of our error object, it makes perfect sense to use our &lt;code&gt;ApplicationException&lt;/code&gt; from the previous session.&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\Exceptions&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\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;JsonEncodeException&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;ApplicationException&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt;   &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;status&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt;       &lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;HTTP_BAD_REQUEST&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="err"&gt;   &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;help&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt;       &lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;trans&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'exception.json_not_encoded.help'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="err"&gt;   &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;error&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt;       &lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;trans&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'exception.json_not_encoded.error'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="err"&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;Notice that once we extend the &lt;code&gt;ApplicationException&lt;/code&gt; class, we have the obligation to implement the status, help, and error functions. Inside these functions, we implemented the return of the values that make sense in the context of this exception.&lt;/p&gt;

&lt;p&gt;In this specific example, we are returning HTTP status 400, and we are getting translated texts from Laravel’s translating scheme.&lt;/p&gt;

&lt;p&gt;Keeping all your messages and texts in Laravel’s translation structure is always a good decision. Having to translate an app after a lot of written code is often more difficult and requires much more refactoring than starting the app with this pattern.&lt;/p&gt;




&lt;p&gt;Now our custom exception structure and encapsulation of errors are done.&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

</description>
      <category>php</category>
      <category>laravel</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Laravel's exceptions: Part 1 – What are exceptions?</title>
      <dc:creator>Jack Miras</dc:creator>
      <pubDate>Thu, 10 Feb 2022 02:00:23 +0000</pubDate>
      <link>https://dev.to/jackmiras/laravels-exceptions-part-1-what-are-exceptions-2ma5</link>
      <guid>https://dev.to/jackmiras/laravels-exceptions-part-1-what-are-exceptions-2ma5</guid>
      <description>&lt;p&gt;An exception is an event that occurs during the execution of a program that disrupts the normal flow of instructions. PHP uses exceptions to handle errors and other exceptional events.&lt;/p&gt;

&lt;p&gt;As in many other languages, an exception can be thrown and caught. You can throw an exception using the &lt;code&gt;throw&lt;/code&gt; keyword, which in PHP 8 became an expression that may be used in any expression context, while in previous versions it was a statement that had to be in its line.&lt;/p&gt;

&lt;p&gt;To facilitate the catching of exceptions, the code should be surrounded by a &lt;code&gt;try&lt;/code&gt; block that must have at least one matching &lt;code&gt;catch&lt;/code&gt; or &lt;code&gt;finally&lt;/code&gt; blocks. If an exception gets thrown and its current scope doesn’t have a catchable block, the exception will “bubble up” or be sent to a “higher scope”.&lt;/p&gt;

&lt;p&gt;If the handling of an exception implements both the &lt;code&gt;catch&lt;/code&gt; and &lt;code&gt;finally&lt;/code&gt; blocks, be advised that all &lt;code&gt;finally&lt;/code&gt; blocks encountered in the way of the exception event will be executed, even when the event has already passed through the &lt;code&gt;catch&lt;/code&gt; block.&lt;/p&gt;

&lt;p&gt;Finally, if an exception goes all the way to the global scope without finding a matching catchable block, your code will terminate with a fatal error unless the app has a global exception handler, like the one that Laravel has.&lt;/p&gt;

&lt;h3&gt;
  
  
  Content
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Throwing exceptions&lt;/li&gt;
&lt;li&gt;The try and catch blocks&lt;/li&gt;
&lt;li&gt;The finally block&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Throwing exceptions
&lt;/h3&gt;

&lt;p&gt;Now that we understand the structure around exception events, let’s see a couple of examples of how we can throw and catch exceptions.&lt;/p&gt;

&lt;p&gt;Let’s say we want to parse a PHP object to JSON; we would probably use the &lt;code&gt;json_encode()&lt;/code&gt; function for that. This function will not always be able to transform the given object to JSON for various reasons, and when this happens, the function will return &lt;code&gt;false&lt;/code&gt; to let us know that the transformation failed.&lt;/p&gt;

&lt;p&gt;In some ways, we can say that if the transformation of the object fails, our code gets disrupted from the normal flow of instructions since we instructed the code to get us a JSON, and we got a boolean instead.&lt;/p&gt;

&lt;p&gt;With that being said, let’s see in the example down below, how we can use an exception to trigger an event informing that something out of the normal flow has happened.&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="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nv"&gt;$props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &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;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$lastName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&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;props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="s1"&gt;'name'&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="s1"&gt;'last_name'&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;lastName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &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;toJson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nv"&gt;$jsonEncoded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;json_encode&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="n"&gt;props&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$options&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&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;$jsonEncoded&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;JsonEncodeException&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$jsonEncoded&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&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;The &lt;code&gt;toJson()&lt;/code&gt; function is responsible for transforming his class into JSON; as mentioned before, we were going to use the &lt;code&gt;json_encode()&lt;/code&gt; which is being called at the first line of the function and has its returned value stored at the &lt;code&gt;$jsonEncoded&lt;/code&gt; object.&lt;/p&gt;

&lt;p&gt;Next, we have a conditional that checks if the &lt;code&gt;$jsonEncoded&lt;/code&gt; is &lt;code&gt;false&lt;/code&gt;, and if it is, an exception will be thrown because the normal flow of our code got disrupted.&lt;/p&gt;

&lt;p&gt;Then, if the flow of our code didn’t get disrupted, we would just return the &lt;code&gt;$jsonEncoded&lt;/code&gt; object, which at this point is a JSON with the correspondent values of the props from our Person class.&lt;/p&gt;

&lt;h3&gt;
  
  
  The try and catch blocks
&lt;/h3&gt;

&lt;p&gt;To catch the exception potentially thrown by the Person class, we have to use a &lt;code&gt;try&lt;/code&gt; with a matching &lt;code&gt;catch&lt;/code&gt; block, as the example down below shows.&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="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nv"&gt;$person&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;Person&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Jack'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Miras'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nv"&gt;$personAsJson&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$person&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;toJson&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;JsonEncodeException&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="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Exception has been caught"&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;On the first line of the &lt;code&gt;try&lt;/code&gt; block, we are creating a person object, passing a name and a last name as parameters in its constructor.&lt;/p&gt;

&lt;p&gt;Next, we call the &lt;code&gt;toJson()&lt;/code&gt; function out of the &lt;code&gt;$person&lt;/code&gt; object. If the object got correctly transformed into JSON, the &lt;code&gt;$personAsJson&lt;/code&gt; object would receive a JSON string as a result. Otherwise, an exception would be thrown, and the &lt;code&gt;catch&lt;/code&gt; block would be triggered.&lt;/p&gt;

&lt;p&gt;Thereafter, if an exception gets thrown and the &lt;code&gt;catch&lt;/code&gt; block gets triggered, it would first check if the exception being intercepted is an instance of the JsonEncodeException class. If that’s the case, the &lt;code&gt;catch&lt;/code&gt; block would take this exception event, passing it to its handling block, which is printing a message telling that the exception has been caught.&lt;/p&gt;

&lt;h3&gt;
  
  
  The finally block
&lt;/h3&gt;

&lt;p&gt;Another way of handling the exception potentially thrown by the Person class would be to use a &lt;code&gt;finally&lt;/code&gt; block to match the &lt;code&gt;try&lt;/code&gt; block defined, as the example below shows.&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="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nv"&gt;$person&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;Person&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Jack'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Miras'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nv"&gt;$personAsJson&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$person&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;toJson&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Converting person to JSON failed"&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;As in the previous example, at the &lt;code&gt;try&lt;/code&gt; block, we are creating a person object and calling the &lt;code&gt;toJson()&lt;/code&gt; function out of it. If the object gets correctly transformed, the &lt;code&gt;$personAsJson&lt;/code&gt; would receive a JSON string. Otherwise, an exception would be thrown.&lt;/p&gt;

&lt;p&gt;Thereafter, if an exception gets thrown, the &lt;code&gt;finally&lt;/code&gt; block will be triggered even though a catch block has already handled the exception event.&lt;/p&gt;

&lt;p&gt;If that’s the case, the &lt;code&gt;finally&lt;/code&gt; block would take in this exception event and print a message telling that the conversion of the person object into JSON failed.&lt;/p&gt;




&lt;p&gt;Now that you have a more in-depth understanding of what exceptions are and what they are used for, it’s time for us to move on to the next post in this series.&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

</description>
      <category>php</category>
      <category>laravel</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Xdebug in PhpStorm with Docker</title>
      <dc:creator>Jack Miras</dc:creator>
      <pubDate>Fri, 17 Dec 2021 10:45:14 +0000</pubDate>
      <link>https://dev.to/jackmiras/xdebug-in-phpstorm-with-docker-2al8</link>
      <guid>https://dev.to/jackmiras/xdebug-in-phpstorm-with-docker-2al8</guid>
      <description>&lt;p&gt;In my last post, I talked about how to configure &lt;a href="https://dev.to/jackmiras/xdebug-in-vscode-with-docker-379l"&gt;Xdebug in VSCode with Docker&lt;/a&gt;. Now, I would like to share how we can build upon our previous Dockerfile in such a way that Xdebug can run directly from Docker and also connect it with PhpStorm.&lt;/p&gt;

&lt;p&gt;By choosing this approach, we substantially reduce the amount of setup that each team member has to do on their machine to get the project up and running, which means that we can start writing code faster.&lt;/p&gt;

&lt;p&gt;So, why is this so important? Recent &lt;a href="https://www.jetbrains.com/lp/devecosystem-2022/php/#how-do-you-usually-debug-php-code-" rel="noopener noreferrer"&gt;research from JetBrains&lt;/a&gt; shows that 62% of PHP developers debug their code using var_dump(), die(), dd(), and dump().  From my perspective, there is nothing wrong with that. Even if you do it by choice and not because you lack knowledge.&lt;/p&gt;

&lt;p&gt;I'm included in the 62% of developers who debug their code with auxiliary functions instead of using a full-featured debug solution such as Xdebug. I'm a heavy Neovim user, and I didn't adapt quite well to using Neovim with Xdebug; to me, it is just easier and faster to use my code snippets around the dd() function.&lt;/p&gt;

&lt;p&gt;But occasionally, I catch myself in situations where it would be faster to jump into PhpStorm and just use Xdebug, especially when I'm working with other people who aren't familiar with Vim or Neovim.&lt;/p&gt;

&lt;h3&gt;
  
  
  Content
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
Xdebug config file

&lt;ul&gt;
&lt;li&gt;&lt;a href="//#explaining-xdebug.ini"&gt;Explaining xdebug.ini&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;PhpStorm&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Xdebug config file
&lt;/h3&gt;

&lt;p&gt;Before jumping into PhpStorm, first we have to clear up a few things about Xdebug to fully grasp the changes we’re going to make to the IDE. The information was first introduced on the topic of the &lt;a href="https://dev.to/jackmiras/docker-compose-for-a-laravel-app-ie7#app-command-directive"&gt;command directive&lt;/a&gt; in a previous post. You will notice that at some point a &lt;strong&gt;xdebug.ini&lt;/strong&gt; file gets copied from a local &lt;strong&gt;.docker&lt;/strong&gt; folder into &lt;strong&gt;/etc/php8/conf.d/50_xdebug.ini&lt;/strong&gt; at the container.&lt;/p&gt;

&lt;p&gt;Even though the content of the file got shown, I intentionally didn't explain its content so that we could explore the debugging topic all at once, going all the way from configuring Xdebug to using it with an IDE.&lt;/p&gt;

&lt;p&gt;Down below, we have the same Xdebug config file from the previous post, placed at &lt;strong&gt;.docker/xdebug.ini&lt;/strong&gt; on the root of our Laravel project. Each line of code will be explained further, but in case you want to know every configuration that you can add in this file, check the &lt;a href="https://xdebug.org/docs/all_settings" rel="noopener noreferrer"&gt;Xdebug documentation&lt;/a&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;zend_extension&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;xdebug.so
xdebug.mode&lt;span class="o"&gt;=&lt;/span&gt;develop,coverage,debug,profile
xdebug.idekey&lt;span class="o"&gt;=&lt;/span&gt;docker
xdebug.start_with_request&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;yes
&lt;/span&gt;xdebug.log&lt;span class="o"&gt;=&lt;/span&gt;/dev/stdout
xdebug.log_level&lt;span class="o"&gt;=&lt;/span&gt;0
xdebug.client_port&lt;span class="o"&gt;=&lt;/span&gt;9003
xdebug.client_host&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;YOUR_COMPUTER_IP&amp;gt;


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

&lt;/div&gt;
&lt;h4&gt;
  
  
  Explaining xdebug.ini
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;zend_extension=xdebug.so&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A Zend extension hooks into “lower-level” languages; a single extension can be both a PHP and a Zend extension; despite being very uncommon, it's possible, and Xdebug is a good example of it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;xdebug.mode=develop,coverage,debug,profile&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This setting controls which Xdebug features get enabled; according to the documentation, the following values will get accepted:&lt;/p&gt;

&lt;p&gt;    - develop&lt;br&gt;
        Enables Development Helpers, including the overloaded var_dump().&lt;br&gt;
    - coverage&lt;br&gt;
        Enables Code Coverage Analysis to generate code coverage reports, mainly with PHPUnit.&lt;br&gt;
    - debug&lt;br&gt;
        Enables step-debugging. This can be used to step through your code while it is running, and analyze the values of variables.&lt;br&gt;
    - profile&lt;br&gt;
        Enables Profiling, with which you can analyze performance bottlenecks with tools like CacheGrind.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;xdebug.idekey=docker&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Controls which IDE key Xdebug should pass on to the debugging client or proxy. The IDE Key is only important for use with the DBGp Proxy Tool, although some IDEs are incorrectly picky as to what its value is. The default is based on the DBGP_IDEKEY environment setting. If it is not present, the default falls back to an empty string.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;xdebug.start_with_request=yes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The functionality starts when the PHP request starts, and before any PHP code gets executed. For example, xdebug.mode=trace and xdebug.start_with_request=yes, start a function trace for the whole request.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;xdebug.log=/dev/stdout&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Configure Xdebug's log file, but in this case, we are redirecting the log content to the default stdout of our container.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In case you don't want to see these logs you can comment out this line of your &lt;strong&gt;.docker/xdebug.ini&lt;/strong&gt; file by changing the line to &lt;code&gt;;xdebug.log=/dev/stdout&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;xdebug.log_level=0&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Configures which logging messages should be added to the log file. In this case, we are instructing Xdebug to log only errors in the configuration. If you want to see more information, you can use level 7 for log info or level 10 for log debug.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;xdebug.client_port=9003&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The port to which Xdebug tries to connect on the remote host. Port 9003 is the default for both Xdebug and the Command Line Debug Client. As many clients use this port number, it is best to leave this setting unchanged.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;xdebug.client_host=&amp;lt;YOUR_COMPUTER_IP&amp;gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Configures the IP address or hostname to which Xdebug will attempt to connect when initiating a debugging connection. This address should be the address of the machine where your IDE or debugging client is listening for incoming debugging connections.&lt;/p&gt;

&lt;p&gt;Down below, you can see how to get your IP address correctly in the main OS the developers use. In case you are using a different OS, the commands may serve as a base to try to extrapolate a solution for your use case.&lt;/p&gt;

&lt;p&gt;macOS:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

ipconfig getifaddr en0


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

&lt;/div&gt;

&lt;p&gt;Windows with WSL:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nb"&gt;grep &lt;/span&gt;nameserver /etc/resolv.conf | &lt;span class="nb"&gt;cut&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;' '&lt;/span&gt; &lt;span class="nt"&gt;-f2&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Linux (Debian-based distros):&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nb"&gt;hostname&lt;/span&gt; &lt;span class="nt"&gt;-I&lt;/span&gt; | &lt;span class="nb"&gt;cut&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;' '&lt;/span&gt; &lt;span class="nt"&gt;-f1&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Once you have correctly found your IP address, you can place it into xdebug.client_host as mentioned before, and that will leave you with a directive looking similar to this: xdebug.client_host=192.168.0.158.&lt;/p&gt;

&lt;p&gt;In summary, you've instructed Xdebug to start with a request and try to send the debug events to the host with the IP 192.168.0.158 on port 9003. Since the IP represents your computer, when configuring PhpStorm to connect to Xdebug, the configuration will be extremely similar to when connecting to localhost.&lt;/p&gt;

&lt;h3&gt;
  
  
  PhpStorm
&lt;/h3&gt;

&lt;p&gt;As you may already know, PhpStorm is a proprietary, cross-platform IDE for PHP, built by the Czech Republic-based company JetBrains. PhpStorm provides an editor for PHP, HTML, and JavaScript with on-the-fly code analysis, error prevention, and automated refactorings for PHP and JavaScript code.&lt;/p&gt;

&lt;p&gt;With that being said, you may be wondering: “What do we need to have PhpStorm with all the aspects of an IDE with full-featured debugging”?&lt;/p&gt;

&lt;p&gt;For starters, we need to check if the IDE can properly connect with Docker:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F35shori540bxaxw6b2e1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F35shori540bxaxw6b2e1.png" alt="check-docker-connection" width="800" height="476"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thereafter, we have to configure a PHP server. This can be done by going to Settings &amp;gt; PHP &amp;gt; Servers, then clicking on the plus sign, as the following screenshot shows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp3fbulglz8o783xkpsqk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp3fbulglz8o783xkpsqk.png" alt="php-servers00" width="800" height="476"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you click the plus sign, a form will open, where the Name, Host, Port, and Absolute path of the server have to be filled in:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5klac4fq6l9wzf8n5eg6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5klac4fq6l9wzf8n5eg6.png" alt="php-servers01" width="800" height="476"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Notice that the &lt;em&gt;Port&lt;/em&gt; matches the port from our previsouly built &lt;a href="https://dev.to/jackmiras/docker-compose-for-a-laravel-app-ie7"&gt;docker-compose.yml&lt;/a&gt; and the &lt;em&gt;Absolute path on the server&lt;/em&gt; matches the workdir from our previously built &lt;a href="https://dev.to/jackmiras/laravel-with-php7-4-in-an-alpine-container-3jk6"&gt;Dockerfile&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now, that the server has been created, we can move to the debug configuration. Let's start by clicking on the &lt;em&gt;More Actions&lt;/em&gt; button in the main window, as the next screenshot shows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz1tfici0i17yew5lkjlb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz1tfici0i17yew5lkjlb.png" alt="run-debug-configurations00" width="800" height="634"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, click on the &lt;em&gt;Edit…&lt;/em&gt; option to open the &lt;em&gt;Run/Debug Configurations&lt;/em&gt; window:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feau58mdbcamuxqhxc57s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feau58mdbcamuxqhxc57s.png" alt="run-debug-configurations01" width="800" height="519"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Subsequently, click into &lt;em&gt;Add New Configuration  &amp;gt; PHP Remote Debug&lt;/em&gt; as the screenshot down below shows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw4swboc5uhbc16y18nt9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw4swboc5uhbc16y18nt9.png" alt="run-debug-configurations00" width="800" height="575"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, a form will open, and there, fill the &lt;em&gt;Name&lt;/em&gt; with your Remote Debug configuration; next, check the &lt;em&gt;Filter debug connection by IDE key&lt;/em&gt; option and then select the &lt;em&gt;Server&lt;/em&gt; previously created; and finally, fill the &lt;em&gt;IDE key (session id)&lt;/em&gt; with the same value that got used at the xdebug.idekey directive at our &lt;strong&gt;.docker/xdebug.ini&lt;/strong&gt;. More details are in the illustration below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkantjy4st2lmz2mjhy5e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkantjy4st2lmz2mjhy5e.png" alt="run-debug-configurations03" width="800" height="593"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As a result of the previous steps, the remote debug configuration got finished, and PhpStorm can now start listening for PHP debug connections. Click on the indicated button, as shown:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbxnsr0w4jyvp3t0jo94d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbxnsr0w4jyvp3t0jo94d.png" alt="start-listening-to-php-debug-connections" width="800" height="519"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And then, as a final step, click the debug button. Once the debug is running, you can trigger a request through Postman or your tests, and PhpStorm will intercept the event and stop at the first breaking point found.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6r2oljgf1529zezykm90.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6r2oljgf1529zezykm90.png" alt="debug-docker" width="800" height="519"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Now, Xdebug is finally configured in your PhpStorm, and you can enjoy a more robust debugging tool with the potential to speed up your entire workflow.&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

</description>
      <category>php</category>
      <category>xdebug</category>
      <category>phpstorm</category>
      <category>docker</category>
    </item>
    <item>
      <title>Xdebug in VSCode with Docker</title>
      <dc:creator>Jack Miras</dc:creator>
      <pubDate>Fri, 10 Dec 2021 04:08:09 +0000</pubDate>
      <link>https://dev.to/jackmiras/xdebug-in-vscode-with-docker-379l</link>
      <guid>https://dev.to/jackmiras/xdebug-in-vscode-with-docker-379l</guid>
      <description>&lt;p&gt;In my last post, I talked about how to configure a &lt;a href="https://dev.to/jackmiras/docker-compose-for-a-laravel-app-ie7"&gt;development&lt;/a&gt; environment and how it extends a Dockerfile made for production.&lt;/p&gt;

&lt;p&gt;Now, I would like to share how we can build upon our previous Dockerfile in such a way that Xdebug can run directly from Docker and also connect it with Visual Studio Code.&lt;/p&gt;

&lt;p&gt;By choosing this approach, we substantially reduce the amount of setup that each team member has to do on their machine to get the project up and running, which means that we can start writing code faster.&lt;/p&gt;

&lt;p&gt;So, why is this so important? Recent &lt;a href="https://www.jetbrains.com/lp/devecosystem-2022/php/#how-do-you-usually-debug-php-code-" rel="noopener noreferrer"&gt;research from JetBrains&lt;/a&gt; shows that 62% of PHP developers debug their code using var_dump(), die(), dd(), and dump(). From my perspective, there is nothing wrong with that. Even if you do it by choice and not because you lack knowledge.&lt;/p&gt;

&lt;p&gt;I'm included in the 62% of developers who debug their code with auxiliary functions instead of using a full-featured debug solution such as Xdebug. I'm a heavy Neovim user, and I didn't adapt quite well to using Neovim with Xdebug; it is just easier and faster to use my code snippets around the dd() function.&lt;/p&gt;

&lt;p&gt;But occasionally, I catch myself in situations where it would be faster to jump into Visual Studio Code and just use Xdebug, especially when I'm working with other people who aren't familiar with Vim or Neovim.&lt;/p&gt;

&lt;h3&gt;
  
  
  Content
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
XDebug config file

&lt;ul&gt;
&lt;li&gt;&lt;a href="//#explaining-xdebug.ini"&gt;Explaining xdebug.ini&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;a href="https://dev.tovscode"&gt;Visual Studio Code&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="//#explaining-launch.json"&gt;Explaining launch.json&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Xdebug config file
&lt;/h3&gt;

&lt;p&gt;Before jumping into VSCode, first we have to clear up a few things about Xdebug to fully grasp the changes we’re going to make to the IDE. The information was first introduced on the topic of the &lt;a href="https://dev.to/jackmiras/docker-compose-for-a-laravel-app-ie7#app-command-directive"&gt;command directive&lt;/a&gt; in a previous post. You will notice that at some point a &lt;strong&gt;xdebug.ini&lt;/strong&gt; file gets copied from a local &lt;strong&gt;.docker&lt;/strong&gt; folder into &lt;strong&gt;/etc/php8/conf.d/50_xdebug.ini&lt;/strong&gt; at the container.&lt;/p&gt;

&lt;p&gt;Even though the content of the file got shown, I intentionally didn't explain its content so that we could explore the debugging topic all at once, going all the way from configuring Xdebug to using it with an IDE.&lt;/p&gt;

&lt;p&gt;Down below, we have the same Xdebug config file from the previous post, placed at &lt;strong&gt;.docker/xdebug.ini&lt;/strong&gt; on the root of our Laravel project. Each line of code will be explained further, but in case you want to know every configuration that you can add in this file, check the &lt;a href="https://xdebug.org/docs/all_settings" rel="noopener noreferrer"&gt;Xdebug documentation&lt;/a&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;zend_extension&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;xdebug.so
xdebug.mode&lt;span class="o"&gt;=&lt;/span&gt;develop,coverage,debug,profile
xdebug.idekey&lt;span class="o"&gt;=&lt;/span&gt;docker
xdebug.start_with_request&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;yes
&lt;/span&gt;xdebug.log&lt;span class="o"&gt;=&lt;/span&gt;/dev/stdout
xdebug.log_level&lt;span class="o"&gt;=&lt;/span&gt;0
xdebug.client_port&lt;span class="o"&gt;=&lt;/span&gt;9003
xdebug.client_host&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;YOUR_COMPUTER_IP&amp;gt;


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

&lt;/div&gt;
&lt;h5&gt;
  
  
  Explaining xdebug.ini
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;zend_extension=xdebug.so&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A Zend extension hooks into “lower-level” languages; a single extension can be both a PHP and a Zend extension; despite being very uncommon, it's possible, and Xdebug is a good example of it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;xdebug.mode=develop,coverage,debug,profile&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This setting controls which Xdebug features get enabled; according to the documentation, the following values will get accepted:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- develop
    Enables Development Helpers, including the overloaded var_dump().
- coverage
    Enables Code Coverage Analysis to generate code coverage reports, mainly with PHPUnit.
- debug
    Enables step-debugging. This can be used to step through your code while it is running and analyze the values of variables.
- profile
    Enables Profiling, with which you can analyze performance bottlenecks with tools like CacheGrind.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;xdebug.idekey=docker&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Controls which IDE key Xdebug should pass on to the debugging client or proxy. The IDE Key is only important for use with the DBGp Proxy Tool, although some IDEs are incorrectly picky as to what its value is. The default is based on the DBGP_IDEKEY environment setting. If it is not present, the default falls back to an empty string.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;xdebug.start_with_request=yes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The functionality starts when the PHP request starts and before any PHP code is executed. For example, xdebug.mode=trace and xdebug.start_with_request=yes, start a function trace for the whole request.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;xdebug.log=/dev/stdout&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Configure Xdebug's log file, but in this case, we are redirecting the log content to the default stdout of our container.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In case you don't want to see these logs you can comment out this line of your &lt;strong&gt;.docker/xdebug.ini&lt;/strong&gt; file by changing the line to &lt;code&gt;;xdebug.log=/dev/stdout&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;xdebug.log_level=0&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Configures which logging messages should be added to the log file. In this case, we are instructing Xdebug to log only errors in the configuration. If you want to see more information, you can use level 7 for log info or level 10 for log debug.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;xdebug.client_port=9003&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The port to which Xdebug tries to connect on the remote host. Port 9003 is the default for both Xdebug and the Command Line Debug Client. As many clients use this port number, it is best to leave this setting unchanged.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;xdebug.client_host=&amp;lt;YOUR_COMPUTER_IP&amp;gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Configures the IP address or hostname to which Xdebug will attempt to connect when initiating a debugging connection. This address should be the address of the machine where your IDE or debugging client is listening for incoming debugging connections.&lt;/p&gt;

&lt;p&gt;Down below, you can see how to get your IP address correctly in the main OS the developers use. In case you are using a different OS, the commands may serve as a base to try to extrapolate a solution for your use case.&lt;/p&gt;

&lt;p&gt;macOS:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

ipconfig getifaddr en0


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

&lt;/div&gt;

&lt;p&gt;Windows with WSL:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nb"&gt;grep &lt;/span&gt;nameserver /etc/resolv.conf | &lt;span class="nb"&gt;cut&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;' '&lt;/span&gt; &lt;span class="nt"&gt;-f2&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Linux (Debian-based distros):&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nb"&gt;hostname&lt;/span&gt; &lt;span class="nt"&gt;-I&lt;/span&gt; | &lt;span class="nb"&gt;cut&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;' '&lt;/span&gt; &lt;span class="nt"&gt;-f1&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Once you have correctly found your IP address, you can place it into xdebug.client_host as mentioned before, and that will leave you with a directive looking similar to this: xdebug.client_host=192.168.0.158.&lt;/p&gt;

&lt;p&gt;In summary, you've instructed Xdebug to start with a request and try to send the debug events to the host with the IP 192.168.0.158 on port 9003. Since the IP represents your computer, when configuring Visual Studio Code to connect to Xdebug, the configuration will be extremely similar to when connecting to localhost.&lt;/p&gt;

&lt;h3&gt;
  
  
  Visual Studio Code
&lt;/h3&gt;

&lt;p&gt;As you may already know, Visual Studio Code, or, VSCode for short, is a source-code editor made by Microsoft for Windows, Linux, and macOS. Features include support for debugging, syntax highlighting, intelligent code completion, snippets, code refactoring, and embedded Git.&lt;/p&gt;

&lt;p&gt;With that being said, you may be wondering: “What do we need to have VSCode with all the aspects of an IDE with full-featured debugging?”&lt;/p&gt;

&lt;p&gt;For starters, we will need to install the &lt;a href="https://marketplace.visualstudio.com/items?itemName=xdebug.php-debug" rel="noopener noreferrer"&gt;PHP Debug&lt;/a&gt; official plugin:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgnceu06l7cr9ex7w7drd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgnceu06l7cr9ex7w7drd.png" alt="install-php-debug-plugin"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thereafter, a file called launch.json has to be generated; this file gets used by the debugger in any language, which means that a part of this process can be reused when configuring the debugger on VSCode for other languages.&lt;/p&gt;

&lt;p&gt;You can generate the file by clicking in &lt;em&gt;Run and Debug &amp;gt; Create a launch.json file &amp;gt; PHP&lt;/em&gt;, as the following screenshot shows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftuvd2ox04kf0iyeqhxx4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftuvd2ox04kf0iyeqhxx4.png" alt="setting-up-debug"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, the &lt;strong&gt;launch.json&lt;/strong&gt; file will be created with a specification of &lt;code&gt;version&lt;/code&gt; and a &lt;code&gt;configurations&lt;/code&gt; array with three configurations: &lt;code&gt;Listen for Xdebug&lt;/code&gt;, &lt;code&gt;Launch currently open script&lt;/code&gt; and &lt;code&gt;Launch Built-in web server&lt;/code&gt;, as the screenshot shows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg50c5oyelytff2n5l6dv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg50c5oyelytff2n5l6dv.png" alt="debug-launch-json-with-configurations"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, to properly configure the &lt;strong&gt;launch.json&lt;/strong&gt; file, you have to replace the &lt;code&gt;configurations&lt;/code&gt; array by the following:&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;br&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0.2.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;br&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"configurations"&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;br&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;br&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Listen for XDebug on Docker"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;br&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&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"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;br&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"request"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"launch"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;br&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"port"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;9003&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;br&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"pathMappings"&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;br&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"/var/www/html/"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"${workspaceFolder}"&lt;/span&gt;&lt;span class="w"&gt;&lt;br&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;br&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;br&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;br&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

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

&lt;/div&gt;
&lt;h4&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Explaining launch.json&lt;br&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;name&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Indicates the name given to a configuration object.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;type&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Indicates the underlying debugger is being used.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;request&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Indicates whether the configuration is intended to &lt;em&gt;launch&lt;/em&gt; the program or &lt;em&gt;attach&lt;/em&gt; to an already running instance.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;port&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Indicates the port on which to listen for Xdebug&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;pathMappings&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Indicates a mapping of server paths to local paths.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When using /var/www/html/ as key, VSCode knows that the files at the container are under that path, and by using the ${workspaceFolder} as value, VSCode knows that locally the project files are under the current opened directory.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Lastly, as a final step, click on the &lt;code&gt;Start Debugging&lt;/code&gt; button and set the breaking points wherever you need.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2e8829wenyykaanocrza.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2e8829wenyykaanocrza.png" alt="debug-docker"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, Xdebug is finally configured in your VSCode, and you can enjoy a more robust debugging tool with the potential to speed up your entire workflow.&lt;/p&gt;




&lt;p&gt;I encourage you to leave this launch.json file with its content in the project, so other team members can just clone the project, run the containers, and enjoy a full-featured debug solution running in a container environment.&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

</description>
      <category>php</category>
      <category>xdebug</category>
      <category>vscode</category>
      <category>docker</category>
    </item>
    <item>
      <title>Moving large amounts of data on AWS</title>
      <dc:creator>Jack Miras</dc:creator>
      <pubDate>Mon, 15 Nov 2021 01:55:02 +0000</pubDate>
      <link>https://dev.to/jackmiras/moving-large-amounts-of-data-on-aws-3ndg</link>
      <guid>https://dev.to/jackmiras/moving-large-amounts-of-data-on-aws-3ndg</guid>
      <description>&lt;p&gt;Recently, my team got tasked with decoupling all the images from a monolith that was public and had to become privately accessible, but we were also asked to keep the images publicly accessible to be consumed by a frontend app.&lt;/p&gt;

&lt;p&gt;Our frontend app has access to the monolithic API through an API gateway. The gateway is in the same VPC as the monolith that became private, and therefore it can reach him. In my team, there is a strategy to carefully reduce these major apps into microservices and headless frontends.&lt;/p&gt;

&lt;p&gt;To achieve our goal, we decided to move over 50 GB of images from an EFS storage disk into an S3 bucket and update the image references in the monolith database. In that way, we would achieve the goal of having a private app with public images.&lt;/p&gt;

&lt;p&gt;At first, my approach was to use AWS CLI by connecting to the server attached to the EFS through SSH and using AWS CLI to sync all the images into the S3 bucket by using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws s3 &lt;span class="nb"&gt;sync&lt;/span&gt; /var/www/html/app/media s3://app-production-media
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach works, and if you have been tasked with something similar, you will achieve your goal, but this approach isn't the fastest. It took us 2 hours to sync 7 GB of data into the S3 bucket; at that pace, we would've spent more than 14 hours before finishing the synchronization of the images if we didn't get a timeout error, which we did.&lt;/p&gt;

&lt;p&gt;Keep in mind that the &lt;code&gt;aws s3&lt;/code&gt; command got executed on an AWS server in the AWS network, which is way faster than the internet connection at my office, so these 14 hours have a higher weight, given the circumstances.&lt;/p&gt;

&lt;p&gt;So, how could we move these 50 GB of images in an acceptable amount of time? That's where AWS DataSync comes in; this AWS service is meant to move data between the commonly used AWS storage solutions such as EFS, FSx, S3, NFS, Object Storage and SMB.&lt;/p&gt;

&lt;p&gt;You do it by creating a DataSync task that can run only once or be scheduled to run from time to time. My recommendation is that you take a full look at the AWS DataSync documentation, so you can have a full view of DataSync's features.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This article shows how to create a task that runs manually. If you have a different use case, this article will serve you only as a base, and you will have to check the AWS documentation to implement extra aspects in your DataSync task.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Provisioning DataSync task
&lt;/h3&gt;

&lt;p&gt;At the AWS management console, click on the search bar, search for &lt;code&gt;DataSync&lt;/code&gt; and click on the service indicated in the image down below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcma6o8h3b0v5iuawhe5i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcma6o8h3b0v5iuawhe5i.png" alt="aws-management-console-datasync"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  DataSync home page
&lt;/h3&gt;

&lt;p&gt;After clicking it, you will be redirected to the following page: Notice that here you have access to a brief explanation of what DataSync is, how it works, and its benefits and features. Even though this article is straightforward, my recommendation is that you read everything on the DataSync home page. After finishing the reading, you can proceed to the next step by clicking on the &lt;strong&gt;Tasks&lt;/strong&gt; option on the left-side menu.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fywn35g9bqmd9w6w2s3p5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fywn35g9bqmd9w6w2s3p5.png" alt="datasync-home"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Task dashboard
&lt;/h3&gt;

&lt;p&gt;Once you've accessed the &lt;strong&gt;Tasks&lt;/strong&gt; dashboard, you will see an empty dashboard with a Create Task button on the top-right side of the page. Click on the button to be redirected to the page that will allow you to start filling in the information about the DataSync task you will be creating.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1tllqxgmq5h3pi4fkwx9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1tllqxgmq5h3pi4fkwx9.png" alt="datasync-task-panel"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Source location
&lt;/h3&gt;

&lt;p&gt;Here, you must configure the source location from which the data will be copied. As mentioned previously, we will be copying data from an EFS disk into an S3 bucket. Hence, our source location will be pointing to an EFS disk, and down below, you can check how to configure the source location.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fai2a8g14w0j1pmog9uvz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fai2a8g14w0j1pmog9uvz.png" alt="datasync-configure-source-location"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Destination location
&lt;/h3&gt;

&lt;p&gt;After configuring the source location, you will be asked to configure the destination location, which will be an S3 bucket. Make sure to create and configure your bucket in such a way that your application can later read the files. Down below, you can check how to configure the destination location.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcxsr4r4qs1wuustq2i3o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcxsr4r4qs1wuustq2i3o.png" alt="datasync-configure-destination-location"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Configure settings
&lt;/h3&gt;

&lt;p&gt;Once the source and destination locations are configured, you've got to handle general configuration settings such as task name, execution configuration, data transfer configuration, schedule, tags, and logging. Down below, you can check in more detail how to handle these general configurations.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When configuring the Task Logging, you can use a previously created &lt;strong&gt;CloudWatch log group&lt;/strong&gt;, or just hit the &lt;strong&gt;Autogenerate&lt;/strong&gt; button.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frrnknmo241014px8f0ch.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frrnknmo241014px8f0ch.png" alt="datasync-configure-settings"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Review settings
&lt;/h3&gt;

&lt;p&gt;Now that you've configured the task, it is time to review the configurations you've filled in. Read the review page carefully; if anything seems out of order, go back to the step where you found the mistake and fix it. Thereafter, come back to the review page, and once everything is the way you want it to be, you can click on the &lt;strong&gt;Create&lt;/strong&gt; button in the bottom-right corner of the page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm2rwyj4mibjj6wpile93.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm2rwyj4mibjj6wpile93.png" alt="datasync-configure-settings"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Task start
&lt;/h3&gt;

&lt;p&gt;Finally, the task got created, and now it's time to start it and initialize the process of copying the files from EFS to S3. To accomplish that, you just need to click on &lt;strong&gt;Start&lt;/strong&gt; &amp;gt; &lt;strong&gt;Start with default&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy6dhfhdx1lpkch2crvtz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy6dhfhdx1lpkch2crvtz.png" alt="datasync-start"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Task status
&lt;/h3&gt;

&lt;p&gt;Now that the task has started running, you can just watch the &lt;strong&gt;Task status&lt;/strong&gt; until it is concluded. In case you want to see more details about the data getting copied from the EFS to S3, you can click on the &lt;strong&gt;Running&lt;/strong&gt; status under &lt;strong&gt;Task status&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fji3chq9xhh2qbf8br9k1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fji3chq9xhh2qbf8br9k1.png" alt="datasync-see-execution-details"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Execution status
&lt;/h3&gt;

&lt;p&gt;Once you are watching the execution status, you can check a wide variety of information, including performance and the amount of data transferred. You will notice that at first the execution status will be &lt;strong&gt;Launching&lt;/strong&gt;, but it will change as the data sync process keeps going.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl5qhf8mup9j1g8ew0rsg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl5qhf8mup9j1g8ew0rsg.png" alt="datasync-execution-details"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Now that your DataSync task is finally done, you will have all of your data in a S3 bucket in a matter of minutes, not 14 hours.&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>datasync</category>
      <category>devops</category>
      <category>sre</category>
    </item>
  </channel>
</rss>
