<?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: Peter Hrobar</title>
    <description>The latest articles on Forem by Peter Hrobar (@peter_hrobar_b781fa053702).</description>
    <link>https://forem.com/peter_hrobar_b781fa053702</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%2F1071013%2Fcb293c3b-aacf-4ee6-808a-56487cd05031.png</url>
      <title>Forem: Peter Hrobar</title>
      <link>https://forem.com/peter_hrobar_b781fa053702</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/peter_hrobar_b781fa053702"/>
    <language>en</language>
    <item>
      <title>Supercharge Laravel’s validation with value objects</title>
      <dc:creator>Peter Hrobar</dc:creator>
      <pubDate>Tue, 13 Jun 2023 09:18:32 +0000</pubDate>
      <link>https://forem.com/peter_hrobar_b781fa053702/supercharge-laravels-validation-with-value-objects-2hg</link>
      <guid>https://forem.com/peter_hrobar_b781fa053702/supercharge-laravels-validation-with-value-objects-2hg</guid>
      <description>&lt;p&gt;Laravel is a popular PHP framework that provides a robust and flexible validation system for handling user input and ensuring data integrity.&lt;/p&gt;

&lt;p&gt;Laravel’s validation system allows you to define validation rules for incoming data and easily validate it against those rules.&lt;/p&gt;

&lt;p&gt;The validation system in Laravel offers several features and benefits:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Convenient syntax&lt;/strong&gt;: Laravel provides a fluent and expressive syntax for defining validation rules. You can specify the rules directly in your controller or form request classes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rule-based validation&lt;/strong&gt;: You can define validation rules for various types of input data, such as strings, numbers, dates, emails, and more. Laravel offers a wide range of built-in validation rules that cover common use cases. For example, you can validate that a field is required, has a specific length, matches a regular expression, or exists in a database table.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom validation rules&lt;/strong&gt;: Laravel allows you to define your own custom validation rules. This feature is handy when you have specific validation requirements unique to your application.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error messages&lt;/strong&gt;: When validation fails, Laravel automatically generates helpful error messages that you can display to the user. You can easily access these error messages and display them in your views.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Conditional validation&lt;/strong&gt;: Laravel’s validation system supports conditional validation rules. You can specify that certain rules should only be applied if specific conditions are met. For example, you can validate a field as required only if another field has a certain value.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Form request validation&lt;/strong&gt;: Laravel encourages the use of form request classes, which encapsulate the validation logic for a specific form or request. These classes centralize the validation rules, making your code more organized and maintainable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validation with database integration&lt;/strong&gt;: Laravel allows you to validate input against your database records. You can perform unique rule validation to ensure that a value is unique in a specific table column.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;Overall, Laravel’s validation system provides a convenient and powerful way to validate user input, enforce data integrity, and handle validation errors in a structured manner. It helps in improving the security, reliability, and user experience of your applications.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;In programming, a value object is a concept from domain-driven design (DDD) that represents an immutable object whose equality is based on its attribute values rather than its identity. A value object’s main purpose is to encapsulate a set of related attributes or values into a single logical unit.&lt;/p&gt;

&lt;p&gt;In PHP, value objects can be implemented as classes with private properties and getter methods, ensuring that the internal state cannot be modified once the object is created. Value objects typically have no identity and are compared based on their attribute values. This means that two value objects with the same attribute values are considered equal.&lt;/p&gt;

&lt;p&gt;Here are some benefits of using value objects in PHP or any other programming language:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Clarity and expressiveness&lt;/strong&gt;: By using value objects, you can give meaningful names to the data structures in your domain model. Value objects represent concepts and behaviours within your application, making the code more expressive and self-explanatory.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Immutability&lt;/strong&gt;: Value objects are immutable, meaning their state cannot be changed after creation. This immutability guarantees that the data they hold remains consistent and cannot be accidentally modified. Immutability also simplifies reasoning about code since you don’t have to worry about unexpected changes to objects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Encapsulation and data integrity&lt;/strong&gt;: Value objects encapsulate related attributes, ensuring that the internal state is always valid and consistent. You can enforce business rules and constraints within the value object’s methods, ensuring that the object remains in a valid state.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simplified comparisons&lt;/strong&gt;: Value objects provide a natural way to compare objects based on their attribute values. You can easily check if two value objects are equal without having to compare individual attributes manually.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Domain-specific behaviour&lt;/strong&gt;: Value objects can encapsulate behaviour related to the attributes they represent. By adding methods to value objects, you can define behaviour specific to the domain concept they represent. This helps in keeping the behaviour and the data it operates on closely related and self-contained.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code reuse&lt;/strong&gt;: By using value objects, you can reuse them across different parts of your application or even across multiple projects. Value objects are self-contained units of behaviour and data, making them easily reusable and testable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Strong typing and type safety&lt;/strong&gt;: Value objects provide a way to create strongly typed data structures in dynamically typed languages like PHP. By defining value objects with specific attribute types, you can ensure that the data passed into and returned from your methods is of the correct type.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Overall, using value objects in PHP and other programming languages brings clarity, immutability, encapsulation, and domain-specific behaviour to your code. They help in creating more expressive and maintainable code that accurately represents the concepts and constraints of your domain model.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Laravel’s validation system is flexible enough to handle various types of input, including value objects. Value objects can be used as inputs for validation rules, allowing you to validate and enforce rules specific to the attributes of the value object.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To use value objects in Laravel validation, you can follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Create your value object&lt;/strong&gt;: Define a class for your value object, encapsulating the related attributes and behaviour. Ensure that the value object is immutable and implements appropriate methods for accessing its attribute values.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prepare the input data&lt;/strong&gt;: Before performing validation, you need to extract the attribute values from your value object and prepare them for validation. You can create an array or use Laravel’s toArray() method to convert the value object to an array representation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Define validation rules&lt;/strong&gt;: In your validation rules, you can use the extracted attribute values from the value object as inputs. You can specify the rules directly in your controller or form request classes, similar to how you would validate other input data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Perform validation&lt;/strong&gt;: Use Laravel’s validation mechanism, such as the Validator class or form request validation, to perform the validation. Pass the extracted attribute values as the input data to be validated.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;My data object represents a connection point:&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

namespace App\ValueObjects;
use Illuminate\Contracts\Support\Arrayable;

final class ConnectionPoint implements Arrayable {

    const MAX_PORT_NUMBER = 288;

    // Full format for a connection point: Z199S01P010
    const FORMAT = "Z([0-9]{3})S([0-9]{2})P([0-9]{3})";

    private function __construct(
            private int $zone,
            private int $stripe,
            private int $port,
            private string $name
        ) 
    { }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The class implements the Arrayable interface since we are connecting this with an Eloquent model. In the application we will create a fresh instance of the model from time to time.&lt;/p&gt;

&lt;p&gt;There are only two ways to instantiate our value object:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;using a static conversion method to create a new connection point object&lt;/li&gt;
&lt;li&gt;or creating an empty connection point object
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public static function fromString(string $name = ''): self {
        $parts = preg_match("/^".self::FORMAT."$/si", $name, $matches);

        if ($parts === 0 || $parts === false) {
            throw new \InvalidArgumentException(__("Invalid name argument has been passed: {$name}."));
        }

        list($name, $zone, $stripe, $port) = $matches;

        // Additional checking can be added here if required
        // I just removed mine, since it is not relevant for the topic

        return new self($zone, $stripe, $port, $name);
}

public static function createEmpty(): self {
        return new self(0, 0, 0, '');
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The class is immutable and only allows getting out of data using getter methods and comparing objects to each other:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public function equals(ConnectionPoint $connectionPoint): bool {
        return $this-&amp;gt;hasSameName($connectionPoint) &amp;amp;&amp;amp;
               $this-&amp;gt;hasSameZone($connectionPoint) &amp;amp;&amp;amp;
               $this-&amp;gt;hasSameStripe($connectionPoint) &amp;amp;&amp;amp;
               $this-&amp;gt;hasSamePort($connectionPoint);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let us get to the fun part. Let us connect our value object with an Eloquent model. For this Laravel provides a flexible casting system.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In the context of Laravel’s Eloquent ORM (Object-Relational Mapping), casting refers to the process of transforming the data retrieved from a database into native PHP data types and vice versa.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Eloquent allows you to define casts for specific attributes of your model, enabling you to work with attribute values consistently and conveniently.&lt;/p&gt;

&lt;p&gt;To create a custom cast run the following artisan command:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;php artisan make:cast ConnectionPointCast&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The new cast class will be placed in your app/Casts directory.&lt;/p&gt;

&lt;p&gt;In our custom cast class, we define a getter, a setter and a compare method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class ConnectionPointCast implements CastsAttributes
{
    public function get($model, string $key, $value, array $attributes)
    {
        $f = fn($value) =&amp;gt; $value instanceof ConnectionPoint;

        return match($value) {
            $f($value) =&amp;gt; $value,
            null =&amp;gt; ConnectionPoint::createEmpty(),
            default =&amp;gt; ConnectionPoint::fromString((string) $value)
        };
    }

    public function set($model, string $key, $value, array $attributes)
    {
        // do not forget, that value objects are immutable!
        if ($value instanceof ConnectionPoint) {
            return $value-&amp;gt;getName();
        }

        return (ConnectionPoint::fromString((string) $value))-&amp;gt;getName();
    }

    public function compare($value, $originalValue)
    {
        $value = ConnectionPoint::fromString((string) $value);
        $originalValue = ConnectionPoint::fromString((string) $originalValue);

        return $value-&amp;gt;equals($originalValue);
    }

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

&lt;/div&gt;



&lt;p&gt;I use the &lt;code&gt;compare&lt;/code&gt; method to make sure that in the application when we call &lt;code&gt;getDirty()&lt;/code&gt; on our model then the various model instances are compared correctly.&lt;/p&gt;

&lt;p&gt;As a final step in the Eloquent model, you have to define the custom cast by adding them to the &lt;code&gt;$casts&lt;/code&gt; property:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;protected $casts = [
        'start' =&amp;gt; ConnectionPointCast::class,
        'end' =&amp;gt; ConnectionPointCast::class
];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;Now, let us continue with Laravel validation. To make our value object work with Laravel, we need to create a custom validation object (you might use a closure as well as part of your validation, but if you are re-using these then it is simpler to put them into their class).&lt;/p&gt;

&lt;p&gt;Use the &lt;code&gt;make:rule&lt;/code&gt; Artisan command to generate a new custom validation class. Specify the desired name for your custom rule. For example, let's create a rule called &lt;code&gt;ConnectionPointCompare&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;php artisan make:rule ConnectionPointCompare --invokable&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This will create our new rule in the app/Rules directory of your project.&lt;/p&gt;

&lt;p&gt;Our custom rule implements the &lt;code&gt;DataAwareRule&lt;/code&gt; and the &lt;code&gt;ValidatorAwareRule&lt;/code&gt; interfaces as well, since we need to get access to the validator and its data in our validation logic. You might, or might not need these in your code.&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

namespace App\Rules;

use Illuminate\Contracts\Validation\DataAwareRule;
use Illuminate\Contracts\Validation\InvokableRule;
use Illuminate\Contracts\Validation\ValidatorAwareRule;
use InvalidArgumentException;
use App\ValueObjects\ConnectionPoint;

class ConnectionPointCompare implements DataAwareRule, InvokableRule, ValidatorAwareRule
{

    protected $data = [];
    protected $validator;


    public function __invoke($attribute, $value, $fail)
    {
        try {
            $start = ConnectionPoint::fromString((string) $value);
            try {
                $end = ConnectionPoint::fromString((string) $this-&amp;gt;data['end']);
                if (!$start-&amp;gt;compare($end))
                    $fail('validation.connection_point_compare')-&amp;gt;translate();
            } catch (InvalidArgumentException $e) {
                $attributeName = __('validation.attributes.' . 'end');
                $errorMessage = __('validation.connection_point_format', [
                    'attribute' =&amp;gt; $attributeName,
                    'value' =&amp;gt; $this-&amp;gt;data['end']
                ]);
                $this-&amp;gt;validator-&amp;gt;errors()-&amp;gt;add('end', $errorMessage);
            }
        } catch (InvalidArgumentException $e) {
            $fail('validation.connection_point_format')-&amp;gt;translate([
                'value' =&amp;gt; $value,
            ]);
        }
    }

    public function setData($data): self {
        $this-&amp;gt;data = $data;
        return $this;
    }

    public function setValidator($validator): self {
        $this-&amp;gt;validator = $validator;
        return $this;
    }

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

&lt;/div&gt;



&lt;p&gt;You can see the power of data objects in the example code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;if we can not instantiate our start connection point then we immediately throw an exception with the relevant error message,&lt;/li&gt;
&lt;li&gt;then we try to do the same for our end connection point. Please notice how we use the validator object and the validation data to access other attributes and their values,&lt;/li&gt;
&lt;li&gt;if we were able to instantiate both connection points then we are ready to compare them. compare() is a method of our value object class that I’m not going to detail here,&lt;/li&gt;
&lt;li&gt;if everything works as expected then we are fine, otherwise, we throw the relevant exception.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;By using value objects in Laravel validation, you can ensure that the input data adheres to the rules specific to the attributes of the value object, promoting data integrity and validation consistency within your application.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;The final part is to integrate our custom validation rules into the validation process.&lt;/p&gt;

&lt;p&gt;There are many way to use validation in Laravel. You can find the detailed documentation for your Laravel version here: [(&lt;a href="https://laravel.com/docs/9.x/validation#custom-validation-rules)"&gt;https://laravel.com/docs/9.x/validation#custom-validation-rules)&lt;/a&gt;]&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;'start' =&amp;gt; [
    'bail',
    'required',
     new ConnectionPointFormat,
     new ConnectionPointLocation,
     new ConnectionPointCompare,
],
'end' =&amp;gt; [
     'bail',
     'required',
     new ConnectionPointFormat,
     new ConnectionPointLocation,
],
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see we can chain our validation rules just like any other rule. I use the bail keyword so after the first unsuccessful validation check the rest is not executed.&lt;/p&gt;

&lt;p&gt;If I have to change the format of a connection point I have to do it in only one place in the entire application and everything else will still work without modification.&lt;/p&gt;

&lt;p&gt;If I would like to change the way I compare these connection points, the validation system will follow ‘automagically’.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Value objects and custom validation provides an elegant and easy way to maintain clarity and expressiveness, encapsulation and data integrity and promotes code reuse throughout your Laravel application.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Just like I promised you at the beginning of this article.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>php</category>
      <category>programming</category>
      <category>valueobjects</category>
    </item>
    <item>
      <title>Chaining events in Laravel</title>
      <dc:creator>Peter Hrobar</dc:creator>
      <pubDate>Wed, 17 May 2023 06:59:59 +0000</pubDate>
      <link>https://forem.com/peter_hrobar_b781fa053702/chaining-events-in-laravel-5apl</link>
      <guid>https://forem.com/peter_hrobar_b781fa053702/chaining-events-in-laravel-5apl</guid>
      <description>&lt;p&gt;The Laravel event management system provides a flexible and powerful mechanism for implementing event-driven architecture in your application. It promotes decoupling, modularity, reusability, and testability while allowing for easy extensibility and adaptability.&lt;/p&gt;

&lt;p&gt;In Laravel, an event is a class that represents a specific occurrence or action that takes place within your application.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Events serve as a way to notify other parts of your application when something significant happens.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Events allow for a decoupled and flexible architecture by separating the logic that triggers an event from the logic that handles the event. This means that different components of your application can be loosely coupled and unaware of each other, making it easier to add or remove functionality without directly modifying existing code.&lt;/p&gt;

&lt;p&gt;When an event is fired in Laravel, it triggers a sequence of actions. These actions can include executing event listeners, sending notifications, updating data, logging, or any other logic you define.&lt;/p&gt;

&lt;p&gt;To create an event run the following artisan command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan make:event CableStatusChanged
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command generates an event class file in the app/Events directory. You can then define properties and methods within this class to encapsulate the data and behavior associated with the event.&lt;/p&gt;

&lt;p&gt;The below code snippet is an example of the CableStatusChange event. It receives its parameters through the constructor and stores them as public 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

namespace App\Events;

use App\Models\Cable;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class CableStatusChanged
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    /**
     * Create a new event instance.
     *
     * @return void
     */
    public function __construct(public Cable $cable, public int $cablePairStatusId) {

    }

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

&lt;/div&gt;



&lt;p&gt;Once you have created an event you need to create an event listener.&lt;/p&gt;

&lt;p&gt;Event listeners are responsible for responding to events and performing actions based on those events.&lt;/p&gt;

&lt;p&gt;When an event is fired in Laravel, it will be dispatched to its corresponding listeners. The listeners can then execute code or perform tasks in response to the event. This allows for the decoupling of different components within your application, making it easier to add or remove functionality without directly modifying the code that triggers the event.&lt;/p&gt;

&lt;p&gt;To create an event listener in Laravel, you can use the artisan command make:listener like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan make:listener ChangeCableStatus --event=CableStatusChanged
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After running the command, Laravel will generate a new listener class file in the app/Listeners directory. You can find and modify this file to define the logic for handling the event. Within the listener class, you'll typically implement the handle() method, which contains the code that should be executed when the event is fired.&lt;/p&gt;

&lt;p&gt;Once you’ve created an event listener, you need to register it in your application. This can be done in the EventServiceProvider class, located in the app/Providers directory. Inside the listen property of the service provider, you can specify the events and their corresponding listeners:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class EventServiceProvider extends ServiceProvider
{
    /**
     * The event to listener mappings for the application.
     *
     * @var array&amp;lt;class-string, array&amp;lt;int, class-string&amp;gt;&amp;gt;
     */
    protected $listen = [
        CableStatusChanged::class =&amp;gt; [
            ChangeCableStatus::class,
            RegisterCableStatusChange::class,
        ]
    ];

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

&lt;/div&gt;



&lt;p&gt;In the above example, you can see how to chain listeners for the same event.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Chaining listeners allows you to define multiple listeners that will be executed sequentially when the event is fired. Each listener in the chain can perform its actions or handle different aspects of the event.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It is important to remember that the order of listeners in the chain matters. If ChangeCableStatus modifies the event data or cancels the event, subsequent listeners may receive different data or not be executed at all. Therefore, it’s important to consider the order of listeners when chaining them.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;By chaining listeners, you can create a modular and flexible event-driven system in Laravel, where different listeners can handle specific aspects of an event or perform different tasks in response to the same event.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class ChangeCableStatus {
    /**
     * Handle the event.
     *
     * @param  \App\Events\CableStatusChanged  $event
     * @return void
     */
    public function handle(CableStatusChanged $event) {
        $event-&amp;gt;cable-&amp;gt;connection_points()
            -&amp;gt;get()
            -&amp;gt;each
            -&amp;gt;update(['cable_pair_status_id' =&amp;gt; $event-&amp;gt;cablePairStatusId]);
    }

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

&lt;/div&gt;



&lt;p&gt;The event listener in the example above receives the event and updates the application database accordingly.&lt;/p&gt;

&lt;p&gt;The reason for using each() method is to enable record-level logging for mass updates in the application.&lt;/p&gt;

&lt;p&gt;In Laravel, you can fire an event using the event() helper function or the Event facade. Here's how you can fire an event using the Eventfacade:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$cablePairStatusIdIsDirty &amp;amp;&amp;amp;
    CableStatusChanged::dispatch($this-&amp;gt;cable, $this-&amp;gt;cablePairStatusId);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In both cases, you’re creating a new instance of the event class (CableStatusChanged) and passing any necessary data as its constructor arguments.&lt;/p&gt;

&lt;p&gt;As a summary let me highlight the advantages of Laravel’s event management system:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Decoupled Architecture&lt;/strong&gt;: Events allow for a decoupled architecture by separating the code that triggers an event from the code that handles the event. This promotes loose coupling between different components of your application, making it easier to modify or extend functionality without directly modifying existing code.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Modularity and Reusability&lt;/strong&gt;: Events provide a modular and reusable approach to handling specific occurrences or actions within your application. You can define events and their corresponding listeners, allowing you to add or remove listeners as needed. This promotes code organization and reusability across different parts of your application.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Flexibility&lt;/strong&gt;: With event-driven architecture, your application becomes more flexible and adaptable. By firing events and attaching listeners, you can easily introduce new features or change existing behavior by adding or modifying event listeners. This promotes scalability and makes it easier to maintain and evolve your application over time.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Improved Testability&lt;/strong&gt;: Events make it easier to write unit tests for specific functionality within your application. You can test event listeners independently, ensuring they respond appropriately to events and perform the expected actions. This improves the overall testability and maintainability of your codebase.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Event Sourcing and Logging&lt;/strong&gt;: Laravel events can be used for event sourcing, where events are stored and used to rebuild the application state. This enables auditing, historical tracking, and undo/redo functionality. Events can also be logged to provide a comprehensive record of important occurrences in your application, facilitating debugging and troubleshooting.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Asynchronous Processing&lt;/strong&gt;: Laravel’s event system supports asynchronous event handling, allowing listeners to be processed asynchronously. This can be particularly useful when dealing with time-consuming or resource-intensive tasks, as it offloads the processing to a background queue, improving performance and responsiveness.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>php</category>
      <category>laravel</category>
      <category>eventdriven</category>
    </item>
    <item>
      <title>Testing with phpbench</title>
      <dc:creator>Peter Hrobar</dc:creator>
      <pubDate>Tue, 16 May 2023 06:19:30 +0000</pubDate>
      <link>https://forem.com/peter_hrobar_b781fa053702/testing-your-code-with-phpbench-2p1p</link>
      <guid>https://forem.com/peter_hrobar_b781fa053702/testing-your-code-with-phpbench-2p1p</guid>
      <description>&lt;h2&gt;
  
  
  Non-functional requirements are often forgotten aspects of code development.
&lt;/h2&gt;

&lt;p&gt;One of the most well-known non-functional requirements is application performance.&lt;/p&gt;

&lt;p&gt;If your application is dealing with a large number of users then this can be translated to various things, typically front-end response time.&lt;/p&gt;

&lt;p&gt;Today, it’s no longer a cliché that your competition is just one click away on the Internet.&lt;/p&gt;

&lt;p&gt;A couple of months back I had to re-write one of my old applications using Laravel and Livewire.&lt;/p&gt;

&lt;p&gt;The application is used to document the cabling layout in a data center. One key feature is the listing of the routes between the connectivity devices. For this purpose, the software uses graph search algorithms, which can explore the paths between the devices and print all the cables along the paths.&lt;/p&gt;

&lt;p&gt;Originally I used a BFS-based approach that was quick enough and worked well in an unweighted and undirected graph.&lt;/p&gt;

&lt;p&gt;I wanted to explore other approaches, such as incorporating weights into the pathfinding functionality of the application and testing various alternatives to BFS.&lt;/p&gt;

&lt;p&gt;In my previous article, I wrote about an algorithm I have developed to find the shortest path between two nodes in a weighted graph. I used Dijkstra’s algorithm with my priority queue to accomplish this.&lt;/p&gt;

&lt;p&gt;I also come up with a bidirectional search algorithm based on ChatGPT-generated pseudo-code. ChatGPT provided its version in Python so I had to rewrite the code to PHP but this was much simpler than I thought.&lt;/p&gt;

&lt;p&gt;PHP rocks again …. please contact me if you are interested in the final code of bidirectional search in PHP.&lt;/p&gt;

&lt;p&gt;After obtaining all three algorithms for comparison, I needed to select a tool that could assist me in comparing their performance.&lt;/p&gt;

&lt;p&gt;An obvious choice was phpbench since it is relatively simple to use and in many aspects, it is similar to phpunit.&lt;/p&gt;

&lt;p&gt;As the phpbench documentation states:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“PHPBench is a benchmark runner for PHP analogous to PHPUnit but for performance rather than correctness”.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After installing phpbench in my project I created a class file that contains my performance test cases:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/**
 * @BeforeMethods({"setUp"})
 */
class GraphTraversalBench
{

    private array $fullGraph = [];

    private int $start, $end;
    private $app;

    protected function initializeGraph(): array { ... }

    public function setUp() {

        ...

        $this-&amp;gt;fullGraph = $this-&amp;gt;initializeGraph();

        // Select start and end device randomly ...
        $this-&amp;gt;start = array_rand($this-&amp;gt;fullGraph);

        do {
            $this-&amp;gt;end = array_rand($this-&amp;gt;fullGraph);
        } while ($this-&amp;gt;end === $this-&amp;gt;start);

    }

    public function benchBFS()
    {
        (new Graph(graph: $this-&amp;gt;fullGraph))-&amp;gt;breadthFirstSearch($this-&amp;gt;start, $this-&amp;gt;end);
    }

    public function benchDijkstraWithPriorityQueue()
    {
        (new Graph(graph: $this-&amp;gt;fullGraph))-&amp;gt;dijkstraWithPriorityQueue($this-&amp;gt;start, $this-&amp;gt;end);
    }

    public function benchBidirectionalSearch()
    {
        (new Graph(graph: $this-&amp;gt;fullGraph))-&amp;gt;bidirectionalSearch($this-&amp;gt;start, $this-&amp;gt;end);
    }

}

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

&lt;/div&gt;



&lt;p&gt;The code is straightforward:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;first, we set up all the class variables so all test methods can use the same graph (fullGraph) with the same start and end nodes,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;then we create a new instance of our Graph and call each search method one by one.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When we run our tests we specify the number of revs and iterations on the command line.&lt;/p&gt;

&lt;p&gt;Since we pick a random start and end node for our testing we define a relatively high number of revs and a relatively low number of iterations.&lt;/p&gt;

&lt;p&gt;As you can see in the figure below we tested 25 pairs of nodes with all 3 algorithms and we run each algorithm a 100 times for the same start and end nodes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--U6pEmboe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ixnf235ld2r8snrpmw9x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--U6pEmboe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ixnf235ld2r8snrpmw9x.png" alt="Benchmarking results for various path finding algorithms" width="800" height="287"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Benchmarking results for various path finding algorithms&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The final results are not surprising.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The bidirectional search algorithm is a basically doing a BFS from the start and the end nodes respectively so this should be the quickest amongst the tested ones.&lt;/p&gt;

&lt;p&gt;BFS is also very quick since we know the start and the end nodes (during testing it was using a non-weighted version of our graph).&lt;/p&gt;

&lt;p&gt;Dijkstra’s algorithm on the other hand is much slower than the other two even with a priority queue based implementation.&lt;/p&gt;

&lt;p&gt;This is due to the fact that it not only finds the path between the two given nodes but it also take into consideration the weight of the edges connecting them.&lt;/p&gt;

&lt;p&gt;Since I was happy with it’s performance I decided to keep the original version of my BFS code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;With the given results I can easily translate the performance implications of switching to an other algorithm that can provide the advantages of using a weighted graph as well.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>php</category>
      <category>performance</category>
      <category>programming</category>
    </item>
    <item>
      <title>Finding the shortest path in a weighted graph with PHP</title>
      <dc:creator>Peter Hrobar</dc:creator>
      <pubDate>Fri, 12 May 2023 14:13:58 +0000</pubDate>
      <link>https://forem.com/peter_hrobar_b781fa053702/finding-the-shortest-path-between-nodes-in-a-weighted-graph-with-php-e34</link>
      <guid>https://forem.com/peter_hrobar_b781fa053702/finding-the-shortest-path-between-nodes-in-a-weighted-graph-with-php-e34</guid>
      <description>&lt;p&gt;&lt;strong&gt;A simple implementation of Dijkstra’s algorithm in PHP&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcp2c77rajuldh3f5f4hf.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%2Fcp2c77rajuldh3f5f4hf.jpg" alt="Highway crossings"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In my last article I shared my code for searching a path in a graph using breath first search.&lt;/p&gt;

&lt;p&gt;BFS works well if the graph is not weighted. By the way if the weight is 1 (or any other constant) for each edge then BFS is basically finding the same path like Dijkstra’s algorithm.&lt;/p&gt;

&lt;p&gt;My implementation allows to select a method that calculates the edge weight so anybody can check the above statement … :-)&lt;/p&gt;

&lt;p&gt;What if our graph has weights for each edge that needs to be taken into consideration?&lt;/p&gt;

&lt;p&gt;Let’s just imagine the road network with the cities as vertexes and the roads as edges.&lt;/p&gt;

&lt;p&gt;If we have to find the shortest path between two cities then obviously the weight of the edge (e.g. the distance between the cities) does matter.&lt;/p&gt;

&lt;p&gt;In my use-case (a datacenter with network devices and cables connecting them) a weight can be also specified. Just think about the OSPF protocol that is also using Dijkstra’s algorithm.&lt;/p&gt;

&lt;p&gt;I have selected a minimum priority queue based approach since it is somewhat quicker that a regular set based solution. I will compare the performance of these algorithms in my next article.&lt;/p&gt;

&lt;p&gt;Unfortunately, neither PHP nor the Ds\PriorityQueue or SplPriorityQueue packages come equipped with a minimum priority queue data structure that meets the stated requirements (as outlined below).&lt;/p&gt;

&lt;p&gt;So I wrote my own PriorityQueue class that implements the 3 methods needed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;add_with_priority(): adds an item (in our case a vertex) to the priority queue with a priority,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;decrease_priority(): decrease the priority of an item,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;extract_min(): returns the item with the smallest priority from the queue.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My solution is array based but I do not need anything fancier than that.&lt;/p&gt;

&lt;p&gt;The code is pretty straightforward:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public function dijkstraWithPriorityQueue(int $origin, int $destination) {

    $this-&amp;gt;origin = $origin;
    $this-&amp;gt;destination = $destination;

    $dist = [];
    $dist[$origin] = 0;

    $q = new MyPriorityQueue();

    foreach(array_keys($this-&amp;gt;graph) as $vertex) {
        if ($vertex !== $origin) {
            $dist[$vertex] = self::$infinite;
            $this-&amp;gt;setParent($vertex, null);
            $q-&amp;gt;append($vertex, self::$infinite);
        }
    }

    $q-&amp;gt;add_with_priority($origin, 0);

    while($q-&amp;gt;count()) {
        $u = $q-&amp;gt;extract_min();
        if ($u === $destination || $u === 0)
            break; // if we found our destination or there is no such route ...
        foreach($this-&amp;gt;getAdjacentEdgesInSet($u, $q) as $v) {
            $alt = $dist[$u] + $this-&amp;gt;graphEdges($u, $v, $this-&amp;gt;getDistance(...));
            if ($alt &amp;lt; $dist[$v]) {
                $dist[$v] = $alt;
                $this-&amp;gt;setParent($v, $u);
                $q-&amp;gt;decrease_priority($v, $alt);
            }
        }
    }

    $this-&amp;gt;setRoute($this-&amp;gt;extractRoute());

    return $this;

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

&lt;/div&gt;



&lt;p&gt;Let us go through the code line-by-line:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;We set our origin and destination vertexes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Then we initiate a destination matrix holding the current distance between the given node and our origin vertex ($origin).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We create a new instance of my priority queue implementation and set the distance and the parent node for each vertex and append them to the queue. The append() method simply adds the vertexes to the end of the queue without checking their priority, so it is basically an O(1) operation. In our case it is absolutely ok since we know that all vertexes have a priority of self::$infinite.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;After the initialisation we add our origin vertex to the priority queue with the smallest priority.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Then we cycle through our queue extracting the smallest priority item with extract_min().&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If we found one and it is not our destination vertex then we check it’s adjacent vertexes which are still in our priority queue.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The variable $alt holds the length of the path from the $origin vertex to the neighbour vertex $v if it were to go through $u. If this path is shorter than the current shortest path recorded for $v, that current path is replaced with this $alt path, the parent for $v is set to the current vertex $u and the priority of $v is decreased to $alt in our priority queue. These steps are the most important parts of Dijkstra’s algorithm.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;At the end of the method we extract and set the route if any was found.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An interesting part of the code is the way we calculate the weigth of an edge between vertexes $u and $v.&lt;/p&gt;

&lt;p&gt;For this we call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$this-&amp;gt;graphEdges($u, $v, $this-&amp;gt;getDistance(...));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The graphEdges method takes the vertexes and a callable. The callable is then used to calculate the weight.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private function getDistance(int $u, int $v): int {
    return $this-&amp;gt;graph[$u][$v] ?? self::$infinite;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this approach we can easily swap-in a new method to calculate the actual weight and use for example the below one to turn our Dijkstra method into something that resembles a close variant to BFS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private static function alwaysReturnOne(int $u, int $v): int {
    return 1;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's all folks. I hope you enjoyed this article.&lt;/p&gt;

&lt;p&gt;In my next post I will compare the execution time of my BFS, simple queue based Dijkstra and the priority queue based Dijkstra algorithms.&lt;/p&gt;

</description>
      <category>php</category>
      <category>datastructures</category>
      <category>programming</category>
      <category>dijkstra</category>
    </item>
    <item>
      <title>The power of PHP and Laravel</title>
      <dc:creator>Peter Hrobar</dc:creator>
      <pubDate>Mon, 24 Apr 2023 18:51:38 +0000</pubDate>
      <link>https://forem.com/peter_hrobar_b781fa053702/the-power-of-php-and-laravel-1i8e</link>
      <guid>https://forem.com/peter_hrobar_b781fa053702/the-power-of-php-and-laravel-1i8e</guid>
      <description>&lt;p&gt;&lt;em&gt;Decomposition of a code snippet to show-case the usage of anonymous functions, macros and higher-order functions …&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When it comes to the popularity of &lt;a href="https://www.stackscale.com/blog/most-popular-programming-languages/"&gt;programming languages&lt;/a&gt; I never really understand when people are talking about how certain languages are superior to others.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I always thought that there are problems that we need to solve as programmers and we have tools that are best suited than others for the given job.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One of the languages I’m using for quite a while is PHP. I know, I know … Python, Java, C++ and others are better, more secure, they use strict type control and many other things.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But actually when you combine PHP 8.x with a powerful framework like Laravel, there are not many tools that are easier to learn and use for web application development.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A couple of months back I started to re-write an application that I have created many-many years ago. It was originally written in PHP 5.x with a lot of client side Javascript and a MySQL backend. A typical set-up one would say.&lt;/p&gt;

&lt;p&gt;I knew from the beginning that I will use an MVC framework to reduce development time so I took a look on what was out there.&lt;/p&gt;

&lt;p&gt;It turned out that Laravel with PHP 8.x and Laravel Forge worked like a charm for me. &lt;strong&gt;I finished the project way quicker than expected and managed to improve and optimise the application in many places.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In this article I’m not going to show you how I re-wrote my application.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I’m only trying to prove why PHP is still one of the most popular programming language for certain tasks.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The code snippet that I chose for my demonstration is a function that calculates the edges of a graph. To put this into context: edges are network cables connecting nodes, which are actual network devices in a data center.&lt;/p&gt;

&lt;p&gt;Now, let see the code snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public static function populateCablesList(): Builder {

    return count(self::$route)
        ? array_reduce(self::createTuples(),
            fn($q, $tuple) =&amp;gt; $q-&amp;gt;filterRouteSegment($tuple),
            Cable::query()-&amp;gt;with(['cable_type', 'cd_start', 'cd_end', 'owner'])
          )
        : Cable::query()-&amp;gt;whereNull('id'); // Return an empty result

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

&lt;/div&gt;



&lt;p&gt;Let’s go through the above code line-by-line.&lt;/p&gt;

&lt;p&gt;As you can see the function is returning a Laravel Eloquent Builder instance that we can use in other parts of our application to return the relevant Cable models. These models then can be used for formatted reports, data tables, data exports etc.&lt;/p&gt;

&lt;p&gt;If there is a route between point ‘a’ and ‘b’ than our static property $route contains the vertexes or nodes of that route otherwise $route is an empty array.&lt;/p&gt;

&lt;p&gt;Based on whether we have a route in our graph:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;we either return a query that will return all Cable models on the given route or&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;an Eloquent query that will return an empty Laravel collection.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;As you can see we are using the higher order PHP function array_reduce to process our $route.&lt;/p&gt;

&lt;p&gt;The static function createTuples in our case will generate &lt;a href="https://en.wikipedia.org/wiki/Tuple"&gt;tuples&lt;/a&gt; using the vertexes of our route and pass them over to the array_reduce function.&lt;/p&gt;

&lt;p&gt;To give you an example: if $route contains a, b and c vertexes then createTuples will return the following tuples: [a, b] and [b, c].&lt;/p&gt;

&lt;p&gt;The anonymous function will take the actual tuple, generate the required SQL query statement and attach it to the query builder instance. This is basically how we are ‘reducing’ the tuples into a Laravel Eloquent query.&lt;/p&gt;

&lt;p&gt;To generate the required SQL query statement we are using a Laravel macro called filterRouteSegment.&lt;/p&gt;

&lt;p&gt;As you can see it generates an SQL WHERE clause using the actual tuple (our Cable model does not have a direction therefore we need to check it’s connection points at it’s start and end node as well).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Builder::macro('filterRouteSegment',
            fn($tuple) =&amp;gt;
            $this-&amp;gt;orWhere(function ($builder) use ($tuple) {
                $builder-&amp;gt;where(function ($query) use ($tuple) {
                    $query-&amp;gt;where('start', $tuple-&amp;gt;start)-&amp;gt;where('end', $tuple-&amp;gt;end);
                })-&amp;gt;orWhere(function ($query2) use ($tuple) {
                    $query2-&amp;gt;where('start', $tuple-&amp;gt;end)-&amp;gt;where('end', $tuple-&amp;gt;start);
                });
            })
        );
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The last parameter to our higher-order function is it’s initial value.&lt;/p&gt;

&lt;p&gt;It is important to note that in our case we are using eager loading the avoid the classical N+1 problem when loading model relationship data in Laravel.&lt;/p&gt;

&lt;p&gt;With the above example we have demonstrated the use of higher order functions, macros and anonymous functions in PHP together with Laravel.&lt;/p&gt;

&lt;p&gt;With these ‘tools’ we were able to solve a seemingly complex problem with just a few lines of code that is also very easy to read and understand.&lt;/p&gt;

</description>
      <category>php</category>
      <category>laravel</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
