<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Nad Lambino</title>
    <description>The latest articles on Forem by Nad Lambino (@nadlambino).</description>
    <link>https://forem.com/nadlambino</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%2F1098667%2F716aafda-9435-4e3b-927b-40381c6440ee.png</url>
      <title>Forem: Nad Lambino</title>
      <link>https://forem.com/nadlambino</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/nadlambino"/>
    <language>en</language>
    <item>
      <title>Handling File Uploads in Laravel, Automatically.</title>
      <dc:creator>Nad Lambino</dc:creator>
      <pubDate>Wed, 10 Jul 2024 13:15:52 +0000</pubDate>
      <link>https://forem.com/nadlambino/handling-file-uploads-in-laravel-automatically-3mhe</link>
      <guid>https://forem.com/nadlambino/handling-file-uploads-in-laravel-automatically-3mhe</guid>
      <description>&lt;p&gt;Managing your file uploads in Laravel is really easy... or is it? Actually, it is really easy, and you can do this in so many ways which you might or might not like.&lt;/p&gt;

&lt;p&gt;Today, I will introduce you to my first Laravel package which I have created to handle the file uploads for your models, automatically.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/nadlambino/laravel-uploadable" rel="noopener noreferrer"&gt;Laravel Uploadable&lt;/a&gt; takes care of the files from your request and upload them for your model. Below is the detailed documentation to get you started.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Installation&lt;/li&gt;
&lt;li&gt;Usage&lt;/li&gt;
&lt;li&gt;Customizing the Rules and Messages&lt;/li&gt;
&lt;li&gt;Customizing the File Name and Upload Path&lt;/li&gt;
&lt;li&gt;Uploading Files with Custom Options for the Storage&lt;/li&gt;
&lt;li&gt;Manually Processing File Uploads&lt;/li&gt;
&lt;li&gt;Temporarily Disable the File Upload Process&lt;/li&gt;
&lt;li&gt;Uploading Files on Model Update&lt;/li&gt;
&lt;li&gt;Uploading Files that are NOT from the Request&lt;/li&gt;
&lt;li&gt;Relation Methods&lt;/li&gt;
&lt;li&gt;Lifecycle and Events&lt;/li&gt;
&lt;li&gt;Queueing&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;You can install the package via composer:&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 nadlambino/uploadable
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Publish and run the migrations with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php artisan vendor:publish &lt;span class="nt"&gt;--tag&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"uploadable-migrations"&lt;/span&gt;
php artisan migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;IMPORTANT&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can add more fields to the uploads table according to your needs, but the existing fields should remain.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Optionally, you can publish the Upload model using&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php artisan vendor:publish &lt;span class="nt"&gt;--tag&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"uploadable-model"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can publish the config file with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php artisan vendor:publish &lt;span class="nt"&gt;--tag&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"uploadable-config"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Usage
&lt;/h2&gt;

&lt;p&gt;Simply use the &lt;code&gt;NadLambino\Uploadable\Concerns\Uploadable&lt;/code&gt; trait to your model that needs file uploads.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;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;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;NadLambino\Uploadable\Concerns\Uploadable&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;Post&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;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;Uploadable&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, everytime you create or update a post, it will automatically upload the files that are included in your request and it will save the details in &lt;code&gt;uploads&lt;/code&gt; table.&lt;/p&gt;

&lt;h2&gt;
  
  
  Customizing the Rules and Messages
&lt;/h2&gt;

&lt;p&gt;Files from the request should have the following request names:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Request name&lt;/th&gt;
&lt;th&gt;Use Case&lt;/th&gt;
&lt;th&gt;Rules&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;document&lt;/td&gt;
&lt;td&gt;Single document upload&lt;/td&gt;
&lt;td&gt;sometimes, file, mime&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;documents&lt;/td&gt;
&lt;td&gt;Multiple document uploads&lt;/td&gt;
&lt;td&gt;sometimes, file, mime&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;image&lt;/td&gt;
&lt;td&gt;Single image upload&lt;/td&gt;
&lt;td&gt;sometimes, image, mime&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;images&lt;/td&gt;
&lt;td&gt;Multiple image uploads&lt;/td&gt;
&lt;td&gt;sometimes, image, mime&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;video&lt;/td&gt;
&lt;td&gt;Single video upload&lt;/td&gt;
&lt;td&gt;sometimes, mime&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;videos&lt;/td&gt;
&lt;td&gt;Multiple video uploads&lt;/td&gt;
&lt;td&gt;sometimes, mime&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;You can add more fields or override the default ones by defining the protected &lt;code&gt;uploadRules&lt;/code&gt;&lt;br&gt;
method in your model.&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;protected&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;uploadRules&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="c1"&gt;// Override the rules for `document` field&lt;/span&gt;
        &lt;span class="s1"&gt;'document'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'required'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'file'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'mime:application/pdf'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; 

        &lt;span class="c1"&gt;// Add a new field with it's own set of rules&lt;/span&gt;
        &lt;span class="s1"&gt;'avatar'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'required'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'image'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'mime:png'&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;To add or override the rules messages, you can define the protected &lt;code&gt;uploadRuleMessages&lt;/code&gt; method in your model.&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;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;uploadRuleMessages&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s1"&gt;'document.required'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'The file is required.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'document.mime'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'The file must be a PDF file.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'avatar.required'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'The avatar is required.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'avatar.mime'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'The avatar must be a PNG file.'&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;h2&gt;
  
  
  Customizing the file name and upload path
&lt;/h2&gt;

&lt;p&gt;You can customize the file name and path by defining the public methods &lt;code&gt;getUploadFilename&lt;/code&gt; and &lt;code&gt;getUploadPath&lt;/code&gt; in your model.&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;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getUploadFilename&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;UploadedFile&lt;/span&gt; &lt;span class="nv"&gt;$file&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="nb"&gt;str_replace&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="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;microtime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;'-'&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;hashName&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;getUploadPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;UploadedFile&lt;/span&gt; &lt;span class="nv"&gt;$file&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="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getTable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="no"&gt;DIRECTORY_SEPARATOR&lt;/span&gt;&lt;span class="mf"&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="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;getKeyName&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;blockquote&gt;
&lt;p&gt;&lt;strong&gt;IMPORTANT&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Make sure that the file name is completely unique to avoid overriding existing files.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Uploading Files with Custom Options for the Storage
&lt;/h2&gt;

&lt;p&gt;When you're uploading your files on cloud storage, oftentimes you want to provide options like visibility, cache control, and other metadata. To do so, you can define the &lt;code&gt;getUploadStorageOptions&lt;/code&gt; in your uploadable model.&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;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getUploadStorageOptions&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s1"&gt;'visibility'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'public'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'CacheControl'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'max-age=315360000, no-transform, public'&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;h2&gt;
  
  
  Manually processing file uploads
&lt;/h2&gt;

&lt;p&gt;File upload happens when the uploadable model's &lt;code&gt;created&lt;/code&gt; or &lt;code&gt;updated&lt;/code&gt; event was fired.&lt;br&gt;
If you're creating or updating an uploadable model quietly, you can call the &lt;code&gt;createUploads&lt;/code&gt; or &lt;code&gt;updateUploads&lt;/code&gt; method to manually process the file uploads.&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;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;Post&lt;/span&gt; &lt;span class="nv"&gt;$post&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$post&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="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="c1"&gt;// If the post did not change, the `updated` event won't be fired.&lt;/span&gt;
    &lt;span class="c1"&gt;// So, we need to manually call the `updateUploads` method.&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nv"&gt;$post&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;wasChanged&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$post&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;updateUploads&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;blockquote&gt;
&lt;p&gt;&lt;strong&gt;IMPORTANT&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Depending on your configuration, the &lt;code&gt;createUploads&lt;/code&gt; will delete the uploadable model when the upload process fails, while &lt;code&gt;updateUploads&lt;/code&gt; will update it to its original attributes.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Temporarily Disable the File Upload Process
&lt;/h2&gt;

&lt;p&gt;You can temporarily disable the file uploads by calling the static method &lt;code&gt;disableUpload&lt;/code&gt;.&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;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;Post&lt;/span&gt; &lt;span class="nv"&gt;$post&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Temporarily disable the file uploads&lt;/span&gt;
    &lt;span class="nc"&gt;Post&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;disableUpload&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nv"&gt;$post&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="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="c1"&gt;// Do more stuff here...&lt;/span&gt;

    &lt;span class="c1"&gt;// Manually process the uploads after everything you want to do.&lt;/span&gt;
    &lt;span class="nv"&gt;$post&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;updateUploads&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;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;When you are trying to create or update multiple uploadable models, the default behavior of this package is that all of the files from the request will be uploaded and will be attached to all of these models. This is because these models are firing the &lt;code&gt;created&lt;/code&gt; or &lt;code&gt;updated&lt;/code&gt; event which triggers the upload process.&lt;/p&gt;

&lt;p&gt;There are multiple ways to prevent this from happening such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Silently create or update the models that you don't want to have the files being uploaded and attached to them. By doing so, the &lt;code&gt;created&lt;/code&gt; or &lt;code&gt;updated&lt;/code&gt; event won't be fired which will not trigger the upload process.&lt;/li&gt;
&lt;li&gt;Disable the upload process on the specific model by calling the &lt;code&gt;disableUpload()&lt;/code&gt; method.&lt;/li&gt;
&lt;li&gt;Disable the upload process from the &lt;code&gt;NadLambino\Uploadable\Actions\Upload&lt;/code&gt; action itself. The &lt;code&gt;NadLambino\Uploadable\Actions\Upload::disableFor()&lt;/code&gt; method can accept a string class name of a model, a model instance, or an array of each or both. See below example:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;NadLambino\Uploadable\Actions\Upload&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;store&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="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Disable the uploads for all of the instances of Post model during this request lifecycle&lt;/span&gt;
    &lt;span class="nc"&gt;Upload&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;disableFor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Post&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="c1"&gt;// User will be created with the files being uploaded and attached to it&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;create&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;validated&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

    &lt;span class="c1"&gt;// Post will be created without the files being uploaded and attached to it&lt;/span&gt;
    &lt;span class="nc"&gt;Post&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;create&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;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// OR&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;User&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="c1"&gt;// Disable the uploads only for this specific user during this request lifecycle&lt;/span&gt;
    &lt;span class="nc"&gt;Upload&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;disableFor&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="c1"&gt;// $user will be updated without the files being uploaded and attached to it&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;validated&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

    &lt;span class="nv"&gt;$anotherUser&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="mf"&gt;...&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// $anotherUser will be updated with the files being uploaded and attached to it&lt;/span&gt;
    &lt;span class="nv"&gt;$anotherUser&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="mf"&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;Also, there is &lt;code&gt;NadLambino\Uploadable\Actions\Upload::enableFor()&lt;/code&gt; method to let you enable the upload process for the given model. This will just remove the given model class or instance from the list of disabled models. Both of these methods will also work on queued uploads.&lt;/p&gt;

&lt;h2&gt;
  
  
  Uploading files on model update
&lt;/h2&gt;

&lt;p&gt;By default, when you update an uploadable model, the files from the request will add up to the existing uploaded files. If you want to replace the existing files with the new ones, you can configure it in the &lt;code&gt;uploadable.php&lt;/code&gt; config file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="s1"&gt;'replace_previous_uploads'&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or alternatively, you can call the static method &lt;code&gt;replacePreviousUploads&lt;/code&gt; before updating the model.&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;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;Post&lt;/span&gt; &lt;span class="nv"&gt;$post&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Replace the previous uploads&lt;/span&gt;
    &lt;span class="nc"&gt;Post&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;replacePreviousUploads&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nv"&gt;$post&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The process of deleting the previous uploads will only happen when new files were successfully&lt;br&gt;
uploaded.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Uploading files that are NOT from the request
&lt;/h2&gt;

&lt;p&gt;If you wish to upload a file that is not from the request, you can do so by calling the &lt;code&gt;uploadFrom&lt;/code&gt; method. This method can accept an instance or an array of &lt;code&gt;\Illuminate\Http\UploadedFile&lt;/code&gt; or a string path of a file that is uploaded on your &lt;code&gt;temporary_disk&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// DO&lt;/span&gt;
&lt;span class="nv"&gt;$post&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;uploadFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;UploadedFile&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;fake&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;image&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'avatar1.jpg'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// OR&lt;/span&gt;
&lt;span class="nv"&gt;$post&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;uploadFrom&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="nc"&gt;UploadedFile&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;fake&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;image&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'avatar1.jpg'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nc"&gt;UploadedFile&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;fake&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;image&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'avatar2.jpg'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="c1"&gt;// OR&lt;/span&gt;
&lt;span class="nv"&gt;$fullpath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;UploadedFile&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;fake&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;image&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'avatar.jpg'&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;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'tmp'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'uploadable.temporary_disk'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'local'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="nv"&gt;$post&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;uploadFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$fullpath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// OR&lt;/span&gt;
&lt;span class="nv"&gt;$post&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;uploadFrom&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="nv"&gt;$fullpath1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nv"&gt;$fullpath2&lt;/span&gt;
&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="c1"&gt;// OR even a mixed of both&lt;/span&gt;
&lt;span class="nv"&gt;$post&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;uploadFrom&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="nc"&gt;UploadedFile&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;fake&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;image&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'avatar1.jpg'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nv"&gt;$fullpath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="nv"&gt;$post&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;IMPORTANT&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Make sure that you've already validated the files that you're passing here as it does not run any validation like it does when uploading from request.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Relation methods
&lt;/h2&gt;

&lt;p&gt;There are already pre-defined relation method for specific upload type.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Relation for all types of uploads&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;upload&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;MorphOne&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Relation for all types of uploads&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;uploads&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;MorphMany&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Relation for uploads where extension or type is in the accepted image mimes&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;image&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;MorphOne&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Relation for uploads where extension or type is in the accepted image mimes&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;images&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;MorphMany&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Relation for uploads where extension or type is in the accepted video mimes&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;video&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;MorphOne&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Relation for uploads where extension or type is in the accepted video mimes&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;videos&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;MorphMany&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Relation for uploads where extension or type is in the accepted document mimes&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;document&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;MorphOne&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Relation for uploads where extension or type is in the accepted document mimes&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;documents&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;MorphMany&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;blockquote&gt;
&lt;p&gt;&lt;strong&gt;IMPORTANT&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;MorphOne relation method sets a limit of one in the query.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Lifecycle and Events
&lt;/h2&gt;

&lt;p&gt;During the entire process of uploading your files, events are being fired in each step. This comes very helpful if you need to do something in between these steps or just for debugging purposes.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Event&lt;/th&gt;
&lt;th&gt;When It Is Fired&lt;/th&gt;
&lt;th&gt;What The Event Receives When Dispatched&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;NadLambino\Uploadable\Events\BeforeUpload::class&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fired before the upload process starts&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Model $uploadable&lt;/code&gt;, &lt;code&gt;array $files&lt;/code&gt;, &lt;code&gt;UploadOptions $options&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;NadLambino\Uploadable\Events\StartUpload::class&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fired when the upload process has started and its about to upload the first file in the list. This event may fired up multiple times depending on the number of files that is being uploaded&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Model $uploadable&lt;/code&gt;, &lt;code&gt;string $filename&lt;/code&gt;, &lt;code&gt;string $path&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;NadLambino\Uploadable\Events\AfterUpload::class&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fired when the file was successfully uploaded and file information has been stored in the &lt;code&gt;uploads&lt;/code&gt; table. This event may fired up multiple times depending on the number of files that is being uploaded&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Model $uploadable&lt;/code&gt;, &lt;code&gt;Upload $upload&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;NadLambino\Uploadable\Events\CompleteUpload::class&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fired when all of the files are uploaded and all of the necessary clean ups has been made&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Model $uploadable&lt;/code&gt;, &lt;code&gt;Collection $uploads&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;NadLambino\Uploadable\Events\FailedUpload::class&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fired when an exception was thrown while trying to upload a specific file.&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Throwable $exception&lt;/code&gt;, &lt;code&gt;Model $uploadable&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If you want to do something before the file information is stored to the &lt;code&gt;uploads&lt;/code&gt; table, you can define the &lt;code&gt;beforeSavingUpload&lt;/code&gt; public method in your model. This method will be called after the file is uploaded in the storage and before the file information is saved in the database.&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;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;beforeSavingUpload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Upload&lt;/span&gt; &lt;span class="nv"&gt;$upload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Model&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="kt"&gt;void&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$upload&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;additional_field&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"some value"&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;Alternatively, you can statically call the &lt;code&gt;beforeSavingUploadUsing&lt;/code&gt; method and pass a closure.&lt;br&gt;
The closure will receive the same parameters as the &lt;code&gt;beforeSavingUpload&lt;/code&gt; method.&lt;br&gt;
Just make sure that you call this method before creating or updating the uploadable model.&lt;br&gt;
Also, &lt;code&gt;beforeSavingUploadUsing&lt;/code&gt; has the higher precedence than the &lt;code&gt;beforeSavingUpload&lt;/code&gt; allowing you to override it when needed.&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="nc"&gt;Post&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;beforeSavingUploadUsing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Upload&lt;/span&gt; &lt;span class="nv"&gt;$upload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Post&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;use&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$value&lt;/span&gt;&lt;span class="p"&gt;)&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="n"&gt;additional_field&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nv"&gt;$post&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;IMPORTANT&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Remember, when you're on a queue, you are actually running your upload process in a different&lt;br&gt;
application instance so you don't have access to the current application state like the request object.&lt;br&gt;
Also, make sure that the closure and its dependencies you passed to the &lt;code&gt;beforeSavingUploadUsing&lt;/code&gt; method are serializable.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Queueing
&lt;/h2&gt;

&lt;p&gt;You can queue the file upload process by defining the queue name in the config.&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="s1"&gt;'upload_on_queue'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alternatively, you can also call the static method &lt;code&gt;uploadOnQueue&lt;/code&gt;.&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="nc"&gt;Post&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;uploadOnQueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'default'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nv"&gt;$post&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>laravel</category>
      <category>fileuploads</category>
      <category>opensource</category>
    </item>
    <item>
      <title>DI Container: What is it and how to create one</title>
      <dc:creator>Nad Lambino</dc:creator>
      <pubDate>Fri, 01 Sep 2023 11:53:35 +0000</pubDate>
      <link>https://forem.com/nadlambino/di-container-what-is-it-and-how-to-create-one-5dlm</link>
      <guid>https://forem.com/nadlambino/di-container-what-is-it-and-how-to-create-one-5dlm</guid>
      <description>&lt;p&gt;Have you ever wondered how does Laravel provide us an instance of a class that we’re injecting on our controllers? Whether it’s an interface, an abstract class, or a concrete class. It feels like a lot of magic is happening, right? Well, it’s all because of Dependency Injection Container.&lt;/p&gt;

&lt;p&gt;If you don’t have any idea yet about dependency injection, you can read my article about &lt;a href="https://dev.to/nadlambino/solid-principle-with-laravel-1ej7"&gt;SOLID Principle with Laravel&lt;/a&gt; and go to the last section which is about dependency injection.&lt;/p&gt;

&lt;p&gt;Basically, Dependency Injection Container is an object that knows how to instantiate an object and configure all of its dependencies. Whenever we try to inject a class into a controller’s constructor or its method, Laravel’s DI Container tries to resolve and create this object for us, including all of its dependencies. Laravel, as a powerful framework is not just limited to resolving concrete classes but also has a lot of features, such as binding interfaces or abstract classes into concrete class, singleton binding, contextual binding, and many more. In this article, we will try to create our very own DI container with basic functionality, so let's get started.&lt;/p&gt;

&lt;p&gt;To create our DI Container, we will be using PHP’s &lt;a href="https://www.php.net/manual/en/book.reflection.php" rel="noopener noreferrer"&gt;Reflection&lt;/a&gt; API. It is a set of built-in classes and functions in PHP that allows us to inspect the structure of classes, methods, properties, and other objects at runtime. Aside from Reflection API, we can also use &lt;a href="https://www.php-fig.org/psr/psr-11/" rel="noopener noreferrer"&gt;PSR-11: Container interface — PHP-FIG&lt;/a&gt; to have a guide on how we can implement our DI Container. However, I won’t be using it here to keep it short and simple.&lt;/p&gt;

&lt;p&gt;Let us first create our Container class and its properties.&lt;br&gt;
&lt;/p&gt;

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

declare(strict_types=1);

class Container
{

  /** Array of [abstract =&amp;gt; concrete] bindings */
  private array $bindings = [];

  /** Array of resolved instances */
  private array $resolved = [];

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

&lt;/div&gt;



&lt;p&gt;In the above code, &lt;code&gt;$bindings&lt;/code&gt; property will hold all of our bindings. Such example of binding is whenever we inject a &lt;code&gt;StorageInterface&lt;/code&gt; in our controller, we may want it to be an instance of a &lt;code&gt;LocalStorageService&lt;/code&gt; or &lt;code&gt;S3StorageService&lt;/code&gt; depending on our environment.&lt;br&gt;
&lt;/p&gt;

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

declare(strict_types=1);

class Container
{

  /** ...property declarations here */

  /** Add binding into $bindings array */
  public function bind(string $abstract, string $concrete = null): void
  {
    $concrete = $concrete ?? $abstract;

    if (!class_exists($concrete)) {
      throw new Exception("Non-existing $concrete class");
    }

    $this-&amp;gt;bindings[$abstract] = $concrete;
  }
}

/** Example usage */
$container = new Container();
$container-&amp;gt;bind(StorageInterface::class, LocalStorageService::class);

/** FileController constructor */
public function __construct(StorageInterface $storage)
{
  /** 
   * Code goes here using the $storage which we expect to be an 
   * instance of LocalStorageService class 
   */
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next on our code is the &lt;code&gt;bind&lt;/code&gt; method. This method requires a string &lt;code&gt;$abstract&lt;/code&gt; class name or interface name that we will inject on our controller, and an optional string &lt;code&gt;$concrete&lt;/code&gt; class name that we want to be instantiated when the given abstract class was injected. Note that bind method simply binds a concrete class into an abstract class or interface, it’s not yet resolving or instantiating it.&lt;br&gt;
&lt;/p&gt;

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

declare(strict_types=1);

class Container
{

  /** ...property declarations here */

  /** Add binding into $bindings array */
  public function bind(string $abstract, string $concrete = null): void
  { ... }

  /** Create an instance of the give class */
  public function make(string $abstract, string $concrete = null): mixed
  {
    $concrete = $concrete ?? $abstract;

    if (isset($this-&amp;gt;bindings[$abstract])) {
      $class = $this-&amp;gt;bindings[$abstract];
    } else {
      $this-&amp;gt;bind($abstract, $concrete);
      $class = $concrete;
    }

    /** Don't worry about this method for now */
    return $this-&amp;gt;resolve($class);
  }
}

/** Example usage */
$container = new Container();
$container-&amp;gt;bind(StorageInterface::class, LocalStorageService::class);

/** Expected to be an instance of LocalStorageService */
$storage = $container-&amp;gt;make(StorageInterface::class);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next method is the &lt;code&gt;make&lt;/code&gt; which is responsible for creating an instance of the given abstract or concrete class. If &lt;code&gt;$concrete&lt;/code&gt; was not provided, it will use the &lt;code&gt;$abstract&lt;/code&gt; parameter as the concrete class. If we already have a binding for this abstract, we will just use its binding, otherwise, we will bind it so that whenever there’s another class or method that is dependent on this abstract along the same request, we can just use this binding. After we get its concrete class, we will then pass it to the resolve method.&lt;br&gt;
&lt;/p&gt;

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

declare(strict_types=1);

class Container
{

  /** ...property declarations here */

  /** Add binding into $bindings array */
  public function bind(string $abstract, string $concrete = null): void
  { ... }

  /** Create an instance of the give class */
  public function make(string $abstract, string $concrete = null): mixed
  { ... }

  /** Resolve the given class and all of its dependencies */
  public function resolve(string $class): mixed
  {
    /** Immediately return a new instance of the class if its already resolved */
    if ($this-&amp;gt;resolved[$class]) {
      try {
        return new ($this-&amp;gt;resolved[$class]);
      } catch (Throwable) { }
    }

    /** Use ReflectionClass to inspect the given class */
    $reflection = new ReflectionClass($class);
    if (! $reflection-&amp;gt;isInstantiable()) {
      throw new Exception("Unable to instantiate a non-instantiable $class");
    }

    /** Create the class constructor and resolve its dependencies */
    $constructor = $reflection-&amp;gt;getConstructor();
    $dependencies = $constructor ? $this-&amp;gt;resolveDependencies($constructor) : [];

    try {
      /** Return a new instance of the reflected class with its dependencies */
      return $reflection-&amp;gt;newInstanceArgs($dependencies);
    } catch (ReflectionException) {
      $dependencyString = implode(', ', $dependencies);
      throw new Exception("Unable to resolve the following dependencies $dependencyString");
    }
  }

  /** 
   * Returns an array of class dependencies 
   * It can be an instantiated class, or the provided default value
   */
  private function resolveDependencies(ReflectionMethod|ReflectionClass $class): array
  {
    $dependencies = [];

    foreach ($class-&amp;gt;getParameters() as $param) {
      $type = $param-&amp;gt;getType();
      $parameter = $param-&amp;gt;getName();

      if ($param-&amp;gt;isDefaultValueAvailable()) {
        $dependencies[] = $param-&amp;gt;getDefaultValue();
        continue;
      }

      if ($type?-&amp;gt;isBuiltin()) {
        throw new Exception("Unable to resolve built in parameter type");
      }

      if ($type === null) {
        throw new Exception("Unable to resolve missing parameter type");
      }

      $name = $type-&amp;gt;getName();

      if ($this-&amp;gt;resolved[$name]) {
        $dependencies[] = new ($this-&amp;gt;resolved[$name]);
        continue;
      }

      $resolved = $this-&amp;gt;resolve($name);
      $dependencies[] = $resolved;
      $this-&amp;gt;resolved[$name] = $resolved;
    }

    return $dependencies;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lastly, we will have these two methods, &lt;code&gt;resolve&lt;/code&gt; and &lt;code&gt;resolveDependencies&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;resolve&lt;/code&gt; method is the one that is responsible for creating an instance of the given class. If the class was already resolved, it will immediately return that instance. If not, then we will use PHP’s &lt;code&gt;ReflectionClass&lt;/code&gt; class to check if it can be instantiated.&lt;/p&gt;

&lt;p&gt;Next is to get the constructor of the class from Reflection API. &lt;code&gt;$reflection-&amp;gt;getConstructor()&lt;/code&gt; returns null when the class doesn’t have a constructor, meaning that it doesn’t have any dependency, so we can just set the &lt;code&gt;$dependencies&lt;/code&gt; variable to empty array, otherwise, it returns a &lt;code&gt;ReflectionMethod&lt;/code&gt; which we then passed to the &lt;code&gt;resolveDependencies&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;resolveDependencies&lt;/code&gt; method is responsible for resolving all of the method’s parameters, in this case, the class constructor. &lt;code&gt;$class-&amp;gt;getParameters()&lt;/code&gt; returns an array of parameters. We can then inspect each parameter, like its type, name, whether it has default values, get that default value, and check if the type is built in or null if not provided. We can then get the name of its type and use recursion to call the resolve method again to try resolve this parameter.&lt;/p&gt;

&lt;p&gt;We now have a working implementation of a DI Container.&lt;br&gt;
&lt;/p&gt;

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

$container = new Container();
$container-&amp;gt;bind(StorageInterface::class, LocalStorageService::class);

// Instance of the UploadController injected with LocalStorageService class
$uploadController = $container-&amp;gt;make(UploadController::class);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that this is a very basic implementation of a DI Container. It does not have a lot of features which is usually offered by powerful frameworks like Laravel. However, I hope that you have learned new things in this article and get the idea of how it works when we use it on our favorite frameworks.&lt;/p&gt;

&lt;p&gt;Thank you for reading :)&lt;/p&gt;

</description>
      <category>php</category>
      <category>dependencyinjection</category>
      <category>reflectionapi</category>
      <category>laravel</category>
    </item>
    <item>
      <title>Database Normalization: Simplifying your tables</title>
      <dc:creator>Nad Lambino</dc:creator>
      <pubDate>Fri, 04 Aug 2023 06:48:12 +0000</pubDate>
      <link>https://forem.com/nadlambino/database-normalization-simplifying-your-tables-93b</link>
      <guid>https://forem.com/nadlambino/database-normalization-simplifying-your-tables-93b</guid>
      <description>&lt;h4&gt;
  
  
  Database normalization
&lt;/h4&gt;

&lt;p&gt;Is a process in database design that helps eliminate data redundancy and improve data integrity by organizing data into logical and efficient structures. It involves breaking down a database into multiple related tables and defining relationships between them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The main goals of database normalization are:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Minimized data redundancy:&lt;/strong&gt; Normalization eliminates data redundancy by ensuring that each piece of data is stored in only one place. This reduces storage space requirements and avoids inconsistencies that can arise from storing redundant data. It also simplifies data maintenance since updates and modifications need to be made in only one location.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Improved data integrity:&lt;/strong&gt; By organizing data into logical and normalized structures, data integrity is enhanced. Relationships between tables are defined and enforced through constraints, such as primary keys and foreign keys, ensuring the accuracy, consistency, and reliability of data. This reduces the risk of data anomalies and inconsistencies.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Simplified data maintenance:&lt;/strong&gt; Normalization simplifies the process of modifying and updating data. Since data is stored in smaller, more manageable units, changes made to a particular piece of data only need to be applied in one location. This reduces the chances of introducing errors during data maintenance and ensures consistent updates throughout the database.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Enhanced query efficiency:&lt;/strong&gt; Normalized databases typically require less complex and faster queries compared to denormalized databases. With well-defined relationships between tables, queries can be written to retrieve and manipulate data more efficiently. This can improve overall performance and response times in database operations.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Facilitated database design:&lt;/strong&gt; Database normalization provides a systematic approach to database design. It helps designers break down complex data structures into smaller, more manageable tables and define relationships between them. This promotes clarity and organization in the database schema, making it easier to understand, maintain, and extend as the system evolves.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Scalability and flexibility:&lt;/strong&gt; Normalized databases are generally more scalable and flexible. As new requirements arise or the system grows, it is easier to extend and modify a normalized database schema without impacting the existing data or structure. This adaptability is particularly useful in dynamic and evolving systems.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Forms of Database Normalization&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The normalization process involves decomposing a database schema into multiple normalization levels, known as normal forms. The most commonly used normal forms are:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;First Normal Form (1NF):&lt;/strong&gt; Ensures atomicity by eliminating repeating groups and ensuring that each column in a table contains only atomic values.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Second Normal Form (2NF):&lt;/strong&gt; Builds upon 1NF by eliminating partial dependencies. It involves removing columns that depend on only a portion of the primary key and placing them in separate tables.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Third Normal Form (3NF):&lt;/strong&gt; Builds upon 2NF by eliminating transitive dependencies. It involves removing columns that depend on non-key attributes and placing them in separate tables.&lt;/p&gt;

&lt;p&gt;There are higher normal forms beyond 3NF, such as &lt;strong&gt;Boyce-Codd Normal Form&lt;/strong&gt; (BCNF) and &lt;strong&gt;Fourth Normal Form&lt;/strong&gt; (4NF), which address more complex dependencies. The choice of the appropriate normal form depends on the specific requirements and complexity of the database schema. However, in this article, we will be tackling only the first, second, and third normal form.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Examples&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Non-normalized Form&lt;/strong&gt;&lt;/p&gt;

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

&lt;p&gt;In this &lt;strong&gt;non-normalized form&lt;/strong&gt;, the &lt;code&gt;Books&lt;/code&gt; table contains redundancy. The book &lt;em&gt;The Great Gatsby&lt;/em&gt; by &lt;em&gt;F. Scott Fitzgerald&lt;/em&gt; appears twice, leading to data redundancy and potential inconsistencies. If, for example, the author's name was to be updated, it would need to be modified in multiple places.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1st Normal Form&lt;/strong&gt;&lt;/p&gt;

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

&lt;p&gt;In this &lt;strong&gt;1NF form&lt;/strong&gt;, the &lt;code&gt;Books&lt;/code&gt; table has been divided into two separate tables: &lt;code&gt;Books&lt;/code&gt; and &lt;code&gt;Authors&lt;/code&gt;. The &lt;code&gt;Books&lt;/code&gt; table now contains a foreign key, &lt;code&gt;author_id&lt;/code&gt;, which references the primary key in the &lt;code&gt;Authors&lt;/code&gt; table. This eliminates the data redundancy issue, as the author's information is stored in the &lt;code&gt;Authors&lt;/code&gt; table only once.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2nd Normal Form&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8vzmodhrejfj71cer04o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8vzmodhrejfj71cer04o.png" alt="Second normal form 1" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;In this 2NF form, the Category column has been moved to a separate Categories table. This eliminates the partial dependency, where the Category column was dependent on the Book ID rather than the primary key of the table.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3rd Normal Form&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F18cs1qmnqoi4tk2x82yn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F18cs1qmnqoi4tk2x82yn.png" alt="Third normal form 1" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;In this &lt;strong&gt;3NF form&lt;/strong&gt;, a new table called &lt;code&gt;Book_Author&lt;/code&gt; has been introduced to represent the &lt;em&gt;many-to-many&lt;/em&gt; relationship between &lt;code&gt;books&lt;/code&gt; and &lt;code&gt;authors&lt;/code&gt;. This eliminates the transitive dependency, where the relationship between &lt;code&gt;books&lt;/code&gt; and &lt;code&gt;authors&lt;/code&gt; was indirectly dependent on the primary key of the &lt;code&gt;Books&lt;/code&gt; table.&lt;/p&gt;

&lt;p&gt;By following &lt;strong&gt;1NF&lt;/strong&gt;, &lt;strong&gt;2NF&lt;/strong&gt;, and &lt;strong&gt;3NF&lt;/strong&gt;, the database is structured with reduced redundancy, improved data integrity, and more flexible and maintainable data management.&lt;/p&gt;

&lt;p&gt;Normalization is an essential concept in relational database design and is widely used to improve data organization, efficiency, and integrity. However, it's important to strike a balance between normalization and performance, as excessive normalization can lead to increased complexity in querying and joining tables.&lt;/p&gt;

</description>
      <category>database</category>
      <category>mysql</category>
      <category>normalization</category>
      <category>programming</category>
    </item>
    <item>
      <title>SOLID Principle with Laravel</title>
      <dc:creator>Nad Lambino</dc:creator>
      <pubDate>Mon, 31 Jul 2023 01:54:04 +0000</pubDate>
      <link>https://forem.com/nadlambino/solid-principle-with-laravel-1ej7</link>
      <guid>https://forem.com/nadlambino/solid-principle-with-laravel-1ej7</guid>
      <description>&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%2Fgv2n18b64fixaozvbrad.jpg" 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%2Fgv2n18b64fixaozvbrad.jpg" alt="SOLID Principle"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  SOLID Principle with Laravel
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What is SOLID principle?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The SOLID principles are a set of five design principles that aim to guide developers in creating software systems that are modular, maintainable, and extensible. These principles provide guidelines for writing clean, robust, and flexible code. Each principle focuses on a specific aspect of software design and encourages the separation of concerns, flexibility, and adherence to good coding practices. By following the SOLID principles, developers can build software that is easier to understand, test, and modify, leading to improved quality and long-term sustainability.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Benefits of SOLID principle&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Code maintainability:&lt;/strong&gt; SOLID principles promote clean and organized code, making it easier to understand, modify, and maintain over time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code reusability:&lt;/strong&gt; By adhering to SOLID principles, code becomes modular and loosely coupled, allowing for easier reuse in different parts of the application or in future projects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Testability:&lt;/strong&gt; SOLID principles encourage code that is easy to test in isolation, leading to more reliable and effective unit tests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flexibility and adaptability:&lt;/strong&gt; Following SOLID principles results in code that is flexible and can be easily extended or modified to accommodate changing requirements or new features.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Collaboration:&lt;/strong&gt; SOLID principles make code easier to understand and work with, facilitating better collaboration among team members.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability:&lt;/strong&gt; SOLID principles help in building scalable systems by enabling the creation of loosely coupled, modular components that can be easily scaled up or down as needed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reduced time and cost:&lt;/strong&gt; Following SOLID principles from the start of a project can save time and reduce costs by minimizing bugs, refactoring needs, and making changes later in the development cycle.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By addressing these areas, the SOLID principles contribute to overall software quality, maintainability, and developer productivity.&lt;/p&gt;




&lt;h3&gt;
  
  
  Single Responsibility Principle
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;Single Responsibility Principle&lt;/strong&gt; (SRP) states that a class should have only one reason to change. It means that a class should have only one responsibility or job.&lt;/p&gt;

&lt;p&gt;In the context of a Laravel application, let's consider a scenario where we have a &lt;code&gt;UserController&lt;/code&gt; class that handles user-related operations like creating a new user, updating user information, and sending welcome emails. However, this violates the SRP because the class has multiple responsibilities.&lt;/p&gt;

&lt;p&gt;Here's an example that violates the SRP&lt;/p&gt;

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

// UserController.php

class UserController
{
    public function create(Request $request)
    {
        // Validation and user creation logic

        $user = User::create($request-&amp;gt;all());

        $this-&amp;gt;sendWelcomeEmail($user); // Move this responsibility out of UserController
    }

    private function sendWelcomeEmail(User $user)
    {
        // Code to send the welcome email
    }
}


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

&lt;/div&gt;

&lt;p&gt;Here's an example that follows the SRP&lt;/p&gt;

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

// UserController.php

class UserController
{
    public function create(Request $request, EmailService $emailService)
    {
        // Validation and user creation logic

        $user = User::create($request-&amp;gt;all());

        // Delegate the responsibility to the EmailService class
        $emailService-&amp;gt;sendWelcomeEmail($user);
    }
}


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

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

// EmailService.php

class EmailService
{
    public function sendWelcomeEmail(User $user)
    {
        // Code to send the welcome email
    }

    public function sendEmailWithAttachment()
    {
        // Code to send email with attachment
    }
}


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

&lt;/div&gt;

&lt;p&gt;In the refactored code, we extract the responsibility of sending a welcome email into a separate &lt;code&gt;EmailService&lt;/code&gt; class. This separates the concerns, allowing the &lt;code&gt;UserController&lt;/code&gt; to focus solely on user-related operations, while the &lt;code&gt;EmailService&lt;/code&gt; class handles email-related tasks. This makes its functions to be reusable on other controllers or service that needs mail related tasks without repeating our code. This adheres to the SRP, as each class now has a single responsibility, making the code more modular, maintainable, and easier to extend or change in the future.&lt;/p&gt;




&lt;h3&gt;
  
  
  Open-Closed Principle
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;Open-Closed Principle&lt;/strong&gt; (OCP) states that software entities (classes, modules, functions, etc.) should be open for extension but closed for modification. In simple terms, it means that you should be able to add new functionality to a system without modifying its existing code.&lt;/p&gt;

&lt;p&gt;Let's consider an example in a Laravel application where we have a &lt;code&gt;PaymentController&lt;/code&gt; that handles different payment methods: PayPal and Stripe. Initially, the controller has a switch statement to determine the payment method and perform the corresponding actions.&lt;/p&gt;

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

// PaymentController.php

class PaymentController
{
    public function processPayment(Request $request)
    {
        $paymentMethod = $request-&amp;gt;input('payment_method');

        switch ($paymentMethod) {
            case 'paypal':
                $this-&amp;gt;processPayPalPayment($request);
                break;
            case 'stripe':
                $this-&amp;gt;processStripePayment($request);
                break;
            default:
                // Handle unsupported payment method
                break;
        }
    }

    private function processPayPalPayment(Request $request)
    {
        // Code for processing PayPal payment
    }

    private function processStripePayment(Request $request)
    {
        // Code for processing Stripe payment
    }
}


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

&lt;/div&gt;

&lt;p&gt;In the above code, adding a new payment method would require modifying the &lt;code&gt;PaymentController&lt;/code&gt; by adding another case to the switch statement. This violates the OCP because we are modifying the existing code instead of extending it.&lt;/p&gt;

&lt;p&gt;To adhere to the OCP, we can use a strategy pattern to decouple the payment processing logic from the controller and make it open for extension. Here's an updated version:&lt;/p&gt;

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

// PaymentController.php

class PaymentController
{
    private $paymentProcessor;

    public function __construct(PaymentProcessorInterface $paymentProcessor)
    {
        $this-&amp;gt;paymentProcessor = $paymentProcessor;
    }

    public function processPayment(Request $request)
    {
        $this-&amp;gt;paymentProcessor-&amp;gt;processPayment($request);
    }
}


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

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

// PaymentProcessorInterface.php

interface PaymentProcessorInterface
{
    public function processPayment(Request $request);
}


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

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

// PayPalPaymentProcessor.php

class PayPalPaymentProcessor implements PaymentProcessorInterface
{
    public function processPayment(Request $request)
    {
        // Code for processing PayPal payment
    }
}


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

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

// StripePaymentProcessor.php

class StripePaymentProcessor implements PaymentProcessorInterface
{
    public function processPayment(Request $request)
    {
        // Code for processing Stripe payment
    }
}


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

&lt;/div&gt;

&lt;p&gt;Now, to dynamically select the payment processor based on user input, you can leverage Laravel's container and configuration capabilities. Here's an example:&lt;/p&gt;

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

// config/payments.php

return [
    'default' =&amp;gt; 'stripe',
    'processors' =&amp;gt; [
        'paypal' =&amp;gt; PayPalPaymentProcessor::class,
        'stripe' =&amp;gt; StripePaymentProcessor::class,
    ],
];


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

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

// PaymentServiceProvider.php

use Illuminate\Support\Facades\App;
use Illuminate\Support\ServiceProvider;

class PaymentServiceProvider extends ServiceProvider
{
    public function register()
    {
        $this-&amp;gt;app-&amp;gt;bind(PaymentProcessorInterface::class, function ($app) {
            $config = $app['config']-&amp;gt;get('payments');
            $defaultProcessor = $config['default'];
            $processors = $config['processors'];

            $selectedProcessor = $request-&amp;gt;input('payment_method', $defaultProcessor);
            $processorClass = $processors[$selectedProcessor];

            return $app-&amp;gt;make($processorClass);
        });
    }
}


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

&lt;/div&gt;




&lt;h3&gt;
  
  
  Liskov Substitution Principle
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;Liskov Substitution Principle&lt;/strong&gt; (LSP) states that objects of a superclass should be replaceable with objects of its subclasses without affecting the correctness of the program. In simpler terms, it means that subclasses should be able to be used interchangeably with the base class without causing any unexpected behavior.&lt;/p&gt;

&lt;p&gt;Let's consider a real-world example where we have a base class called Vehicle and two subclasses called Car and Bicycle. Each of them has a method called &lt;code&gt;startEngine()&lt;/code&gt;, which represents starting the engine of the vehicle.&lt;/p&gt;

&lt;p&gt;Here's an example that violates the Liskov Substitution Principle:&lt;/p&gt;

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

class Vehicle {
    public function startEngine() {
        // Default implementation for starting the engine
        echo "Engine started!";
    }
}



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

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

class Car extends Vehicle {
    public function startEngine() {
        // Implementation specific to starting a car's engine
        echo "Car engine started!";
    }
}



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

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

class Bicycle extends Vehicle {
    public function startEngine() {
        // Bicycles don't have engines, so this violates LSP
        throw new Exception("Bicycles don't have engines!");
    }
}



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

&lt;/div&gt;

&lt;p&gt;In the above code, the Bicycle class violates the Liskov Substitution Principle because it throws an exception when trying to start the engine. This behavior is unexpected and breaks the principle.&lt;/p&gt;

&lt;p&gt;Here's an example that follows the Liskov Substitution Principle:&lt;/p&gt;

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

class Vehicle {
    // Common implementation for all vehicles
    public function startEngine() {
        // Default implementation for starting the engine
        echo "Engine started!";
    }
}



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

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

class Car extends Vehicle {
    public function startEngine() {
        // Implementation specific to starting a car's engine
        echo "Car engine started!";
    }
}



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

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

class Bicycle extends Vehicle {
    // Bicycles don't have engines, so we don't override the startEngine() method
}



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

&lt;/div&gt;

&lt;p&gt;In the above code, the Bicycle class follows the Liskov Substitution Principle by not overriding the &lt;code&gt;startEngine()&lt;/code&gt; method. Since bicycles don't have engines, the default implementation from the base class is used, which is acceptable and doesn't introduce unexpected behavior.&lt;/p&gt;

&lt;p&gt;By following LSP, you ensure that your code is more maintainable, extensible, and less prone to bugs, as you can safely use objects of subclasses wherever objects of the base class are expected.&lt;/p&gt;




&lt;h3&gt;
  
  
  Interface Segregation Principle
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;Interface Segregation Principle&lt;/strong&gt; (ISP) states that clients should not be forced to depend on interfaces they do not use. In simpler terms, it means that a class should not be forced to implement methods that it doesn't need. &lt;/p&gt;

&lt;p&gt;Let's consider a real-world example of an online store application built with Laravel.&lt;/p&gt;

&lt;p&gt;Violating the Interface Segregation Principle:&lt;/p&gt;

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

interface PaymentGatewayInterface {
    public function processPayment($amount);
    public function refundPayment($transactionId);
    public function voidPayment($transactionId);
}



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

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

class PaymentGateway implements PaymentGatewayInterface {
    public function processPayment($amount) {
        // Process payment logic
    }

    public function refundPayment($transactionId) {
        // Refund payment logic
    }

    public function voidPayment($transactionId) {
        // Void payment logic
    }
}



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

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

class EcommerceService {
    private $paymentGateway;

    public function __construct(PaymentGatewayInterface $paymentGateway) {
        $this-&amp;gt;paymentGateway = $paymentGateway;
    }

    public function processOrder($order) {
        // Process order logic

        $this-&amp;gt;paymentGateway-&amp;gt;processPayment($order-&amp;gt;totalAmount);
    }

    public function refundOrder($order) {
        // Refund order logic

        $this-&amp;gt;paymentGateway-&amp;gt;refundPayment($order-&amp;gt;transactionId);
    }

    public function voidOrder($order) {
        // Void order logic

        $this-&amp;gt;paymentGateway-&amp;gt;voidPayment($order-&amp;gt;transactionId);
    }
}



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

&lt;/div&gt;

&lt;p&gt;In this example, the &lt;code&gt;PaymentGatewayInterface&lt;/code&gt; defines three methods: &lt;code&gt;processPayment()&lt;/code&gt;, &lt;code&gt;refundPayment(),&lt;/code&gt; and &lt;code&gt;voidPayment()&lt;/code&gt;. However, in the &lt;code&gt;EcommerceService&lt;/code&gt; class, we only need to use the &lt;code&gt;processPayment()&lt;/code&gt; method to handle payment-related operations. The &lt;code&gt;refundPayment()&lt;/code&gt; and &lt;code&gt;voidPayment()&lt;/code&gt; methods are not relevant to the &lt;code&gt;EcommerceService&lt;/code&gt;, but we're still forced to depend on them because the interface enforces their implementation.&lt;/p&gt;

&lt;p&gt;Here's a modified version that follows the ISP:&lt;/p&gt;

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

interface PaymentProcessorInterface {
    public function processPayment($amount);
}



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

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

interface RefundableInterface {
    public function refundPayment($transactionId);
}



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

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

interface VoidableInterface {
    public function voidPayment($transactionId);
}



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

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

class PaymentGateway implements PaymentProcessorInterface, RefundableInterface, VoidableInterface {
    public function processPayment($amount) {
        // Process payment logic
    }

    public function refundPayment($transactionId) {
        // Refund payment logic
    }

    public function voidPayment($transactionId) {
        // Void payment logic
    }
}



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

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

class EcommerceService {
    private $paymentProcessor;

    public function __construct(PaymentProcessorInterface $paymentProcessor) {
        $this-&amp;gt;paymentProcessor = $paymentProcessor;
    }

    public function processOrder($order) {
        // Process order logic

        $this-&amp;gt;paymentProcessor-&amp;gt;processPayment($order-&amp;gt;totalAmount);
    }
}



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

&lt;/div&gt;

&lt;p&gt;In this updated example, the &lt;code&gt;PaymentProcessorInterface&lt;/code&gt; defines only the &lt;code&gt;processPayment()&lt;/code&gt; method, which is the only method needed by the &lt;code&gt;EcommerceService&lt;/code&gt;. The &lt;code&gt;RefundableInterface&lt;/code&gt; and &lt;code&gt;VoidableInterface&lt;/code&gt; are created for other classes that require those specific functionalities. By separating the interfaces, we adhere to the ISP by allowing clients to depend only on the interfaces they actually need.&lt;/p&gt;

&lt;p&gt;This adherence to the ISP improves the codebase's maintainability, reduces unnecessary dependencies, and makes it easier for entry-level developers to understand and work with the code.&lt;/p&gt;




&lt;h3&gt;
  
  
  Dependency Inversion Principle
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;Dependency Inversion Principle&lt;/strong&gt; (DIP) states that high-level modules should not depend on low-level modules, but both should depend on abstractions. In other words, instead of depending on specific implementations, modules should rely on interfaces or abstract classes.&lt;/p&gt;

&lt;p&gt;Code Sample Violating DIP in Laravel using the Storage Facade:&lt;/p&gt;

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

class UserController extends Controller
{
    public function store(Request $request)
    {
        $avatar = $request-&amp;gt;file('avatar');

        // Violation: The UserController depends directly on the Storage facade.
        // This makes it tightly coupled to the Laravel's file storage implementation.
        $path = Storage::disk('local')-&amp;gt;put('avatars', $avatar);

        // ...
    }
}



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

&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;UserController&lt;/code&gt; class relies on the Storage facade and calls its disk and put methods directly. By depending on the Storage facade directly, the UserController is tightly coupled to the specific file storage system implemented by Laravel, making it harder to switch to a different storage mechanism without modifying the &lt;code&gt;UserController&lt;/code&gt; code.&lt;/p&gt;

&lt;p&gt;Code Sample Following &lt;strong&gt;DIP&lt;/strong&gt; in Laravel using the Storage Service:&lt;/p&gt;

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

interface FileStorage
{
    public function storeFile($directory, $file);
}



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

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

class LocalFileStorage implements FileStorage
{
    public function storeFile($directory, $file)
    {
        return Storage::disk('local')-&amp;gt;put($directory, $file);
    }
}



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

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

class S3FileStorage implements FileStorage
{
    public function storeFile($directory, $file)
    {
        return Storage::disk('s3')-&amp;gt;put($directory, $file);
    }
}



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

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

class UserController extends Controller
{
    private $fileStorage;

    public function __construct(FileStorage $fileStorage)
    {
        $this-&amp;gt;fileStorage = $fileStorage;
    }

    public function store(Request $request)
    {
        $avatar = $request-&amp;gt;file('avatar');

        // The UserController depends on the FileStorage abstraction, which can be
        // implemented using different storage systems.
        $path = $this-&amp;gt;fileStorage-&amp;gt;storeFile('avatars', $avatar);

        // ...
    }
}



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

&lt;/div&gt;

&lt;p&gt;The UserController class now depends on the FileStorage interface instead of directly relying on the Storage facade or a specific implementation. This interface serves as an abstraction that defines the contract for file storage operations.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;S3FileStorage&lt;/code&gt; class implements the &lt;code&gt;FileStorage&lt;/code&gt; interface and provides the concrete implementation for storing files in AWS S3. By injecting the &lt;code&gt;FileStorage&lt;/code&gt; interface into the &lt;code&gt;UserController&lt;/code&gt; constructor, the controller is decoupled from the specific storage mechanism and depends only on the abstraction.&lt;br&gt;
This adherence to the Dependency Inversion Principle allows for easier interchangeability of storage implementations. You can easily introduce new implementations of the FileStorage interface (e.g., a LocalFileStorage class) without modifying the UserController code. The choice of storage mechanism can be determined at runtime or through configuration (.env file), providing flexibility and maintainability.&lt;/p&gt;




&lt;h3&gt;
  
  
  Conclusion:
&lt;/h3&gt;

&lt;p&gt;The SOLID principles are guidelines for writing clean and maintainable code. While they offer numerous benefits, they should not be seen as rigid rules that must always be followed without exception. It's crucial to strike a balance between applying the SOLID principles and considering other factors such as project complexity.&lt;/p&gt;

&lt;p&gt;Thank you for reading.&lt;/p&gt;

</description>
      <category>solid</category>
      <category>laravel</category>
      <category>codequality</category>
      <category>programming</category>
    </item>
    <item>
      <title>How I structure my CSS</title>
      <dc:creator>Nad Lambino</dc:creator>
      <pubDate>Fri, 14 Jul 2023 06:42:33 +0000</pubDate>
      <link>https://forem.com/nadlambino/how-i-structure-my-css-3he8</link>
      <guid>https://forem.com/nadlambino/how-i-structure-my-css-3he8</guid>
      <description>&lt;p&gt;When doing CSS, I always recommend doing it with mobile-first approach. This way, we can ensure that we cover each breakpoint for better responsiveness.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// default or mobile devices (up to 719px)
.heading {
  font-size: 14px;
  padding: 10px;
}

// tablet devices (720px up to 991px)
@media screen and (min-width: 720px) and (max-width: 991px) {
  .heading {
    font-size: 18px;
    padding: 20px;
  }
}

// small screen desktop devices (992px up to 1023px)
@media screen and (min-width: 992px) and (max-width: 1023px) {
  .heading {
    font-size: 18px;
    padding: 30px;
  }
}

// large screen desktop devices (1024px up to 1920px or more)
@media screen and (min-width: 1024px) {
  .heading {
    font-size: 18px;
    padding: 40px;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this approach, we can be sure that all of the devices' screen sizes were covered. Also, we do not have to put the &lt;code&gt;!important&lt;/code&gt; keyword because we know that none of our styles are overlapping, unless if it was overwritten from another CSS file. &lt;/p&gt;

&lt;p&gt;However, there is still one issue that may occur from this. As we can see, we defined our &lt;code&gt;.heading&lt;/code&gt; class multiple times. If we have a small CSS file, this isn't going to be a problem. But once our CSS file started to contain too many styles for our application, it will be harder for us to track from which of this declaration is for mobile, tablets, small desktops, and large desktops. We have to scroll and scroll just to find the right declaration where we want to do some changes or additions. This could slow us down and sometimes causes frustration.&lt;/p&gt;

&lt;p&gt;To resolve this issue, we can improve this approach with the help of SCSS. One of the features of SCSS, is that we are allowed to nest our styles.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.heading {
  // default or mobile devices (up to 719px)
  font-size: 14px;
  padding: 10px;

  // tablet devices (720px up to 991px)
  @media screen and (min-width: 720px) and (max-width: 991px) {
    font-size: 18px;
    padding: 20px;
  }

  // small screen desktop devices (992px up to 1023px)
  @media screen and (min-width: 992px) and (max-width: 1023px) {
    font-size: 18px;
    padding: 30px;
  }

  // large screen desktop devices (1024px up to 1920px or more)
  @media screen and (min-width: 1024px) {
    font-size: 18px;
    padding: 40px;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, all of our styles for the &lt;code&gt;.heading&lt;/code&gt; class for different screen sizes were defined under a single declaration. It is now more predictable, readable, and scalable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation with Tailwind using the &lt;code&gt;@apply&lt;/code&gt; directive
&lt;/h2&gt;

&lt;p&gt;One of the misuses of tailwind is directly using tailwind classes into html or template files. This makes our html code messy and crowded with bunch of classes. The more it goes like this, the harder it is to read and maintain our codebase. One solution is to use the &lt;code&gt;@apply&lt;/code&gt; directive provided by tailwind. With this, we can apply tailwind classes in a single class, and use that class in our html elements.&lt;/p&gt;

&lt;p&gt;Here’s an example on how to use it and keep the mobile-first pattern implemented.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.heading {
  // default or mobile devices
  @apply text-sm p-[10px];

  // medium size screen
  @apply md:text-base md:p-[20px];

  // large size screen
  @apply lg:text-lg lg:p-[30px];

  // extra large size screen
  @apply xl:text-xl xl:p-[40px];
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's it for today. I hope you learned something from what we've discussed. Thank you for your support :)&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>css</category>
      <category>tailwindcss</category>
    </item>
  </channel>
</rss>
