Web Development Articles

Use PHP Recursion to Calculate the Sum of Multi-dimensional Arrays

0 👍
👎 0
 PHP

For this example I will use PHP to create a script that calculates the sum of a multi-dimensional array of integers.   We need a recursive method to do this.  Well not necessarily in this example because the dimensions of array $numbers is known. So we can just use standard for, foreach or while loops embedded to traverse the array.  However when the structure of $numbers is unknown, recursion is necessary.  

Infact, the only way to traverse this kind of array is with recursion.  At some point you will need to learn recursion.  This example breaks things down and makes it easy to understand.


$numbers = [

   2,

   7,

   5,

   [

       4,

       8,

       6

   ],

   [

       2,

       3,

       [

           9,

           3,

           6

       ],

       4,

       5

   ],

   [

       7,

       8,

       9,

       [

           5,

           5,

           4

       ]

   ]

 ];

 

 function calculate($input)

 {   

   $sum = !is_array($input) ? $input : 0;

   if(is_array($input))

   {

       foreach($input as $child)

       {

           $sum += calculate($child);

       }

   }

   return $sum;

 }

 

 $sum = calculate($numbers);

 

// Ouput: 102

 

 
So recursion is especially useful for traversing a multi-dimensional array where the depth/dimensions are unknown so typical for, while and foreach loops don't work.

PHP Ternary Operator ? :

0 👍
👎 0
 PHP

$val = 10;
$total = 0;
$total = $val > 9 ? ($val + 10) : 0;

echo $total; // $val equals 20

Here is another example:

   $newValue = $val ?: 9;

In this example $newValue is 10.  Notice when $val is NOT null the $newVal will be the value of $val otherwise it's the value behind ?: which is 9 in this case.

Upload and Resize an Image with Laravel Vue and ImageMagick

0 👍
👎 0
 Laravel
 VueJS
 PHP
 ImageMagick
 Bootstrap

In this example I use the Laravel and Vue frameworks to implement a SPA tool to upload images and display a list of images that have been uploaded.  The application also demonstrates image resizing with the amazing PHP ImageMagick library.  So there are a few prerequisits to get started however I won't cover that in this tutorial.  I've added some links to get you through the prerequisits:

  1. Install imagemagick and the pecl imagemagick package. Configure the extension in php.
  2. Install and set-up Laravel to use the Vue 2 Options API with Webpack compiler.
  3. Create required Controllers, Blade Views, routes(web.php, api.php, routes.js) and Vue components

Assuming you have an initial setup you will need to generate an API controller to handle requests made from the Vue components.  You can generate the controller with php artisan:

php artisan make:controller Api/ImageController

Next, we need to specify a directory to store these images.  For this tutorial we will upload our images to /public/images.  So notice in the ImageController the method public_path('images/'.$imageName) is used to specify this location.

 

/app/Http/Controllers/Api/ImageController.php

We need two methods to handle the functionality for this application.  An index method for GET requests to retrieve a list of all images.  And an upload method to handle a POST request to upload an image.

 

<?php

namespace App\Http\Controllers;

 

use Illuminate\Http\Request;

use Illuminate\Support\Facades\File;

use Imagick;

 

class ImageController extends Controller

{

   /**

    * index

    */

   public function index()

   {

       $fileNames = [];

       $imagesPath = public_path('images/');

       $files = File::files($imagesPath);

       foreach ($files as $key=>$file) {

           $fileNames[] = [

               'file'=>$file->getFilename(),

               'path'=>$file->getPathname(),

               'size'=>$file->getSize(),

               'ext'=>$file->getExtension()

           ];

       }

       return response()->json($fileNames);

   }

 

 

   /**

    * upload

    */

   public function upload(Request $request)

   {

       $request->validate([

           'image' => 'required|image|mimes:jpeg,png,jpg,gif,svg|max:2048',

       ]);

 

       // Create a new Imagick object

       $imagick = new Imagick();

 

       // Read the uploaded image

       $imagick->readImage($request->file('image')->getPathname());

 

       // Resample the image (change the resolution)

       $imagick->resizeImage(100, 100, Imagick::FILTER_LANCZOS, 1);

 

       // Save the image

       $imageName = time() . '.' . $request->file('image')->getClientOriginalExtension();

       $imagick->writeImage(public_path('images/' . $imageName));

 

       // Clear the Imagick object

       $imagick->clear();

       $imagick->destroy();

 

       $fileNames = [];

       $imagesPath = public_path('images/');

       $files = File::files($imagesPath);

       foreach ($files as $file) {

           $fileNames[] = [

               'file'=>$file->getFilename(),

               'path'=>$file->getPathname(),

               'bytes'=>$file->getSize(),

               'ext'=>$file->getExtension()

           ];

       }

      

       return response()->json($fileNames);

   }
}

 

/resources/js/Image/Upload.vue

The Upload.vue component will display an image upload form and a script to interact with the form actions.  Once the user selects an image, they will be able to preview the image before upload.  Notice the API request made with Axios POST to /api/images.  These routes are specified in /routes/api.php

<template>

   <div class="container">

       <div class="row justify-content-center">

           <div class="col-md-8">

               Upload Image Form

                   <div class="row m-1 g-1">

                       <div class="form-group col-md-12">

                           <input class="form-control" :class="[{'text-danger': 'image' in errors && errors.image.length > 0}]" type="file" @change="onFileChange" name="image" id="image"  accept="image/*" >

                       </div>

                       <div v-if="'image' in errors" class="text-danger">                

                           <span v-for="(error, index) in errors['image']" :key="'type-'+index">

                               {{error}}

                           </span>

                       </div>

                   </div>

                   <div v-if="preview" class="mt-3">

                       <img :src="preview" alt="preview" width="100" height="100" />

                   </div>

                   <div class="row m-1 g-1">

                       <div class="form-group col-12">

                           <button type="button" @click.prevent="cancelUpload" class="btn btn-sm btn-fw btn-danger float-end mx-2">

                               Cancel

                           </button>

                           <button class="btn btn-sm btn-fw btn-primary float-end" type="submit" @click.prevent="uploadImage">Upload Image</button>

                       </div>

                   </div>

           </div>

       </div>

   </div>

</template>

<script>
export default {

 

   data() {

       return {

           image: null,

           preview: null,

           user: {},

           errors:{

               image: []

           },

       };

   },

 

   methods: {

       cancelUpload(){

           let redirectTo = this.$route.query.redirect || { name: 'admin-images' };

           this.$router.push(redirectTo);

       },

       async uploadImage(){

           if(this.image)

           {

               let fd = new FormData();

               fd.append('image', this.image);

               try {

                   let resp = (await axios.post('/api/images', fd)).data.data;

                   let redirectTo = this.$route.query.redirect || { name: 'admin-images' };

                   this.$router.push(redirectTo);

               } catch(error) {

                   this.errors = error;

               }

           }

           else {

               this.errors.image.push(`An image file is required for upload.`);

           }

          

       },

       onFileChange(e) {

           let file = e.target.files[0];

           if (file) {

               this.image = file;

               this.preview = URL.createObjectURL(file);

           }

       }

   },

   created() {

       console.log('Image/Upload COMPONENT CREATED.');       

   }
}
</script>

 

/resources/admin/js/Image/Index.vue

The Index.vue component will display a list of images that currently exist in the /public/images directory.  Also notice the API GET request made to /api/images.  

<template>

   <div class="container">

       <div class="row justify-content-center">

           <div class="col-md-10">

               <router-link

                   class="btn btn-primary mb-2 float-right"

                   :to="{ name: 'image-upload', query: {redirect: $route.fullPath} }">

                Image Upload

               </router-link>

 

               <div class="mb-4 row" v-for="(image, index) in images" :key="index">

                <img

                       :src="`/images/${image.file}`"

                       class="img-thumbnail "

                       width="100"

                     />

               </div>

           </div>

       </div>

   </div>

</template>

<script>

export default {

   data() {

       return {

           images: [],

           user: {}

       };

   },

   methods: {

   },

   async created() {

       let response = await axios.get("/api/images");

       this.images = response.data.length ? response.data : [];

   }

};

</script>

 

/resources/js/routes.js

In order to see the Image/Index.vue and Image/Upload.vue components we need to specify a route for each in routes.js.  Because the path /images and /image/upload routes are handled via Vue we need to use a <router-link> inside of another Vue component order to navigate to /images and /image/upload.  

<router-link class="nav-link active" :to="{name: 'image-index'}">Images</router-link>
<router-link class="nav-link active" :to="{name: 'image-upload'}">Upload</router-link>

Then configure the routes in /resources/js/routes.js like below:

 

 import ImageIndex from "./Image/Index";

 import ImageUpload from "./Image/Upload";

 

 const routes = [

       // add these 2 new routes

{

    path: "/images",

    component: ImageIndex,

    name: "image-index",

},

{

    path: "/image/upload",

    component: ImageUpload,

    name: "image-upload",

}

 ];

 

 

/routes/api.php

Finally we create API routes to upload and retrieve images.  Notice both routes both go to /images and either Route::get or Route::post will be used to identify them properly in a request.

 

// GET request to ‘/api/images’

Route::get('/images', [App\Http\Controllers\Api\ImageController::class, 'index']);

 

// POST Request to ‘/api/images’
Route::post('/images', [App\Http\Controllers\Api\ImageController::class, 'upload']);

 

 

 

 

 

PHP Anonymous Functions Example Implementation

0 👍
👎 0
 PHP

In PHP, an anonymous method is usually referred to as an anonymous function or a closure. These are functions defined without a name, and they're often used as callbacks or for short-term use.

Here are a few example usages of anonymous methods (closures) in PHP:

  1. Assign to a Variable

    $greet = function($name) {
    return "Hello, $name!";
    };
    echo $greet("Mike"); // Output: Hello, Mike!

  2. Use as Callback (e.g., array_map)

    $numbers = [1, 2, 3, 4];
    $squared = array_map(function($n) { return $n * $n; }, $numbers);
    print_r($squared); // Output: [1, 4, 9, 16]

  3. Use with use to Capture Variables from Parent Scope

    $multiplier = 5;
    $multiply = function($n) use ($multiplier) {
    return $n * $multiplier;
    };
    echo $multiply(10); // Output: 50

  4. Inside of a Class as a Property

    class Greeter {
    public $greet;
    public function __construct() {
    $this->greet = function($name) {
    return "Hi, $name!";
    };
    }
    }
    $greeter = new Greeter();
    echo ($greeter->greet)("Ralph"); // Output: Hi, Ralph!

Remember to wrap class and property inside of parentheses. It's necessary in that specific form because $greeter->greet is a property that holds a closure, not a method. PHP interprets $greeter->greet("Taylor") as trying to call a method named greet, not a closure stored in a property.

5. Anonymous Method Bound to Object (Closure::bind)

class Person {
     private $name = "Secret Name";
}
$getName = function() {
return $this->name;
};
$person = new Person();
$bound = $getName->bindTo($person, 'Person');
echo $bound(); // Output: Secret Name


If you would like more examples or have a question please shoot me a comment. Thanks!

Using Slots in Vue 2 (Options API)

0 👍
👎 0
 Laravel
 VueJS
 NodeJS
 Javascript

Slots in Vue let you create reusable components where the parent controls part of the content. 

 

1. Create a reusable component (Card.vue)

 

 <template>

   <div class="card">

     <div class="card-header">

       <!-- Named slot for header -->

       <slot name="header">Default Header</slot>

     </div>

 

     <div class="card-body">

       <!-- Default slot -->

       <slot>Default content goes here...</slot>

     </div>

 

     <div class="card-footer">

       <!-- Named slot for footer -->

       <slot name="footer">Default Footer</slot>

     </div>

   </div>

 </template>

 

 <script>

 export default {

   name: "Card"

 }

 </script>

 

 

2. Use the component in a parent (App.vue or a Blade-Vue view)

 

 <template>

   <div>

     <h1>Vue 2 Slots Example</h1>

 

     <Card>

       <template v-slot:header>

         Custom Header: Article Info

       </template>

 

       This is the article body content coming from the parent.

 

       <template v-slot:footer>

         <button @click="sayHello">Click Me</button>

       </template>

     </Card>

 

     <!-- Another card with defaults -->

     <Card />

   </div>

 </template>

 <script>

 import Card from "./Card.vue";

 export default {

   name: "App",

   components: { Card },

   methods: {

     sayHello() {

       alert("Hello from slot footer button!");

     }

   }

 }

 </script>

 

 

Javascript Variable Declaration

0 👍
👎 0
 NodeJS
 Javascript

JavaScript has three ways to declare variables, each with different scoping rules and use cases.

When to Use Each

const: Default choice for most variables

let: When you need to reassign values (counters, flags, accumulators)

var: Rarely needed in modern code; mainly for legacy support or specific patterns

The introduction of let and const in ES6 significantly improved JavaScript's variable scoping and made code more predictable and maintainable.

1. var (Function-Scoped)

var is the original way to declare variables in JavaScript. It has function scope and is hoisted to the top of its scope.

Characteristics:

1. Function-scoped (not block-scoped)

2. Hoisted to the top of its scope

3. Can be redeclared and updated

4. Creates a property on the global object (when declared globally)

 

// Function-scoped example

 function doSomething() {

    if (true) {

       var x = 10; // Available throughout the function

    }

    console.log(x); // 10 - accessible outside the block

 }

 

 // Hoisting example

 console.log(y); // undefined (hoisted but not initialized)

 var y = 5;

 

 // Redeclaration

 var z = 1;

 var z = 2; // No error

 console.log(z); // 2

 

2. let (Block-Scoped)

let was introduced in ES6 and provides block-level scoping, which is generally more predictable.

Characteristics:

1. Block-scoped ({ } boundaries)

2. Not hoisted in the same way as var (temporal dead zone)

3. Can be updated but not redeclared in the same scope

4. Doesn't create properties on the global object

Example Use Cases:

 

 // Block-scoped example

 function exampleLet() {

    if (true) {

        let x = 10; // Only available in this block

        console.log(x); // 10

    }

    // console.log(x); // ReferenceError: x is not defined

 }

 

 // Loop variables (ideal use case)

 for (let i = 0; i < 5; i++) {

    setTimeout(() => {

       console.log(i); // Logs 0, 1, 2, 3, 4 (not 5,5,5,5,5 like with var)

    }, 100);

    console.log(i);

 }

 

 // Can be updated but not redeclared

 let count = 0;

 count = 1; // Allowed

 // let count = 2; // SyntaxError: Identifier 'count' has already been declared

 

3. const (Block-Scoped Constants)

const is also ES6 feature for declaring constants - variables that cannot be reassigned.

Characteristics:

1. Block-scoped like let

2. Must be initialized during declaration

3. Cannot be reassigned after declaration

4. For objects/arrays, the reference is constant but properties/elements can be modified

Example Use Cases:

 

 // Constants that shouldn't change

 const PI = 3.14159;

 const API_URL = "https://api.example.com";

 

 // Object with const - properties can be modified

 const person = {

    name: "John",

    age: 30

 };

 person.age = 31; // Allowed - modifying property

 // person = {name: "Jane"}; // Error - cannot reassign

 

 // Array with const - elements can be modified

 const colors = ["red", "green"];

 colors.push("blue"); // Allowed

 // colors = ["purple"]; // Error - cannot reassign

 

 // Configuration objects

 const CONFIG = {

    timeout: 5000,

    retries: 3,

    baseURL: "https://api.example.com"

 };

 

What Happens When You Don't Declare Variable Types in JavaScript

When you don't use var, let, or const to declare a variable, JavaScript automatically creates a global variable (in non-strict mode). This is generally considered bad practice and can lead to bugs.

Problem Scenario:

 

// In file1.js

 function initApp() {

    config = { theme: "dark" }; // Accidentally global

 }

 

 // In file2.js (loaded later)

 function updateConfig() {

    config = { theme: "light" }; // Modifies the same global variable!

 }

 

Solution:

 

 // Always declare variables properly

 function initApp() {

    const config = { theme: "dark" }; // Properly scoped

    return config;

 }

 

 function updateConfig(currentConfig) {

    return { ...currentConfig, theme: "light" }; // No side effects

 }

 


Best Practices

1. Always declare variables with const, let, or var

2. Use 'use strict' to catch undeclared variables

3. Lint your code - tools like ESLint will flag this error

4. Prefer const/let over var for better scoping

 

 // Good

 const calculateTotal = (items) => {

   let total = 0;

   for (let item of items) {

       total += item.price;

   }

   return total;

 };

 

 // Bad (creates global variable)

 const calculateTotalBad = (items) => {

    total = 0; // Missing declaration!

    for (item of items) { // Also missing declaration!

       total += item.price;

    }

    return total;

 };

 

 

Javascript Null Coalescing Operator ??

0 👍
👎 0
 NodeJS

The double question mark ?? in javascript is referred to as the null coalescing operator.  It was introduced in JavaScript ES2020.  It allows you to check for null or undefined variable.   In most cases the order of operation for this operator follows the math and comparison operators.  Below are a few examples: 


Example 1:
let myval = null;
console.log(myval ?? 20); // output is 20 because myval is null

Example 2:
console.log(myval ?? 20); // output is 20 because myval is undefined

Example 3:
let myval = [];
console.log(myval ?? [1,2,3]);  // output is [] because it isn't null and it's not undefined

If the myval is anything other than null or undefined, the output will be the value of the right-hand side of the equation.