Creating Chainable Methods, Everything You need to Know about The Fluent Interface Design Patterns as a PHP Laravel Developer.
Tags: webdev, php, laravel, designpatterns
Published: 2023-07-03 10:20:20



Have you ever marvelled at the elegance and power of chainable methods in the Laravel framework? Do you wonder how the brilliant mind of Taylor Otwell brought this intuitive and efficient design pattern to applicability in your favourite PHP Framework? Whether you're a beginner developer seeking answers, or an advanced developer seeking explanation, you're in the right place!

In this comprehensive blog post, we'll unravel the concepts of the Fluent Design Pattern and explore how it empowers you to write clean, readable, and highly expressive code in PHP, Laravel and beyond. We'll dive deep into the concept, demystify its inner workings, and equip you with the tools to harness its full potential.

## Introduction

Fluent Interface Design Pattern is a popular design pattern in object-oriented programming that allows developers to create more readable and expressive code. This pattern is used to simplify the use of APIs by allowing method chaining and creating a more natural language-like interface. The Fluent Interface Design Pattern provides a concise and expressive way of configuring objects and invoking methods on them.

**Quick Example of Fluent Interface Design Pattern in PHP**

Here's an example of how you can use the Fluent Interface Design Pattern in PHP to create a simple query builder:

```php
class QueryBuilder
{
    protected $table;
    protected $columns = array();
    protected $where = array();
    
    public function table($table)
    {
        $this->table = $table;
        return $this;
    }
    
    public function select($columns)
    {
        $this->columns = is_array($columns) ? $columns : func_get_args();
        return $this;
    }
    
    public function where($column, $operator, $value)
    {
        $this->where[] = compact('column', 'operator', 'value');
        return $this;
    }
    
    public function build()
    {
        $columns = implode(', ', $this->columns);
        $where = '';
        
        if (!empty($this->where)) {
            $where = ' WHERE ';
            foreach ($this->where as $clause) {
                $where .= "{$clause['column']} {$clause['operator']} '{$clause['value']}' AND ";
            }
            $where = rtrim($where, ' AND ');
        }
        
        return "SELECT {$columns} FROM {$this->table}{$where}";
    }
}
```

This class provides a fluent API for building SQL queries. You can use it like this:

```php
$query = (new QueryBuilder())
    ->table('users')
    ->select('name', 'email')
    ->where('age', '>', 18)
    ->where('country', '=', 'USA')
    ->build();

echo $query;
```

This will output the following SQL query:

```
SELECT name, email FROM users WHERE age > '18' AND country = 'USA'
```

In this example, each method in the QueryBuilder class returns `$this`, which allows method chaining. The `table` method sets the table name, the `select` method sets the columns to select, and the `where` method adds WHERE clauses to the query builder, respectively. The `build` method returns the final SQL query as a string.

Now let's take a deeper dive into the concept, the objective benefits and several examples for better understanding.

## What is a Design Pattern?

A design pattern is a reusable solution to a common software design problem. It is a template that can be applied to different situations in software design to solve problems that are similar in nature. Design patterns are not specific to a particular programming language but can be implemented in various programming languages.

Design patterns can be classified into three categories: creational, structural, and behavioral. Creational design patterns deal with object creation mechanisms, trying to create objects in a manner suitable to the situation. Structural design patterns deal with object composition, trying to form large structures of objects. Behavioral patterns focus on communication between objects, and thus provide solutions for communication-related issues.

## What is Fluent Interface Design Pattern?

Fluent Interface Design Pattern is a type of API (Application Programming Interface) design that provides an easy-to-read and expressive interface for configuring objects and invoking methods on them. This pattern is also known as method chaining because it allows you to chain method calls together in a single statement. The result of each method call is an object that can be used to call the next method in the chain.

The Fluent Interface Design Pattern is based on the principle of method chaining. Method chaining is a technique where multiple method calls are chained together in a single statement. Each method in the chain returns an object on which the next method can be called. This creates a fluent and readable interface that makes it easy to configure objects and invoke methods.

The Fluent Interface Design Pattern provides a more natural and intuitive way of using APIs. It makes the code more readable and expressive, which makes it easier to understand and maintain. It also reduces the chances of making errors while using the API.

The Fluent Interface Design Pattern can be used to configure objects, set properties, and invoke methods on them. It can also be used to build complex object hierarchies and create domain-specific languages.

## Why use Fluent Interface Design Pattern?

The Fluent Interface Design Pattern has several benefits that make it a popular choice for API design. Here are some of the benefits of using the Fluent Interface Design Pattern:

**Readability**: The Fluent Interface Design Pattern makes the code more readable and expressive. The chained methods provide a clear and concise way of configuring objects and invoking methods on them.

**Intuitiveness**: The Fluent Interface Design Pattern provides an intuitive way of using APIs. The fluent syntax makes it easy to understand how to use the API without reading the documentation.

**Reduced Errors**: The Fluent Interface Design Pattern reduces the chances of making errors while using the API. The chained methods provide a clear and concise way of configuring objects and invoking methods on them, which reduces the chances of making mistakes.

**Flexibility**: The Fluent Interface Design Pattern provides flexibility in configuring objects and invoking methods on them. It allows you to build complex object hierarchies and create domain-specific languages.

**Maintainability**: The Fluent Interface Design Pattern makes the code more maintainable. The fluent syntax makes it easy to understand and modify the code, which makes it easier to maintain.

## Deep Dive Examples of Fluent Interface Design Pattern

Let's look at more examples of the Fluent Interface Design Pattern.

<u>Example 1: Setting Properties
</u>
Suppose you have a class named Person that has two properties, name and age. You want to set the values of these properties using the Fluent Interface Design Pattern. Here's how you can do it in PHP:

```php
class Person {
    private $name;
    private $age;

    public function setName($name) {
        $this->name = $name;
        return $this;
    }

    public function setAge($age) {
        $this->age = $age;
        return $this;
    }
}

// Using Fluent Interface to Set Properties
$person = (new Person())->setName("John")->setAge(30);
```

In the above example, the `setName` and `setAge` methods return the same object on which they are called. This allows the methods to be chained together to set the values of the `name` and `age` properties.

<u>Example 2: Invoking Methods
</u>
Suppose you have a class named Calculator that has four methods, `add`, `subtract`, `multiply`, and `divide`. You want to perform a series of calculations using the Fluent Interface Design Pattern. Here's how you can do it in PHP:

```php
class Calculator {
    private $result;

    public function add($num) {
        $this->result += $num;
        return $this;
    }

    public function subtract($num) {
        $this->result -= $num;
        return $this;
    }

    public function multiply($num) {
        $this->result *= $num;
        return $this;
    }

    public function divide($num) {
        $this->result /= $num;
        return $this;
    }

    public function getResult() {
        return $this->result;
    }
}

// Using Fluent Interface to Perform Calculations
$calculator = (new Calculator())
    ->add(10)
    ->subtract(5)
    ->multiply(2)
    ->divide(4);
$result = $calculator->getResult(); // Result is 2
```

In the above example, the `add`, `subtract`, `multiply`, and `divide` methods return the same object on which they are called. This allows the methods to be chained together to perform a series of calculations.

<u>Example 3: Creating Domain-Specific Languages
</u>
The Fluent Interface Design Pattern can be used to create domain-specific languages (DSLs) that are tailored to specific domains. DSLs are specialized languages that are designed to solve problems in a specific domain.

Suppose you want to create a DSL for building SQL queries. Here's how you can do it in PHP:

```php
class SqlQueryBuilder {
    private $tableName;
    private $columns = array();
    private $whereClauses = array();

    public function select(...$columns) {
        $this->columns = array_merge($this->columns, $columns);
        return $this;
    }

    public function from($tableName) {
        $this->tableName = $tableName;
        return $this;
    }

    public function where($clause) {
        $this->whereClauses[] = $clause;
        return $this;
    }

    public function build() {
        $queryBuilder = new StringBuilder();
        $queryBuilder->append("SELECT ");
        if (empty($this->columns)) {
            $queryBuilder->append("*");
        } else {
            $queryBuilder->append(implode(", ", $this->columns));
        }
        $queryBuilder->append(" FROM ")->append($this->tableName);
        if (!empty($this->whereClauses)) {
           

 $queryBuilder->append(" WHERE ");
            $queryBuilder->append(implode(" AND ", $this->whereClauses));
        }
        return $queryBuilder->toString();
    }
}

// Using Fluent Interface to Build SQL Queries
$sqlQuery = (new SqlQueryBuilder())
    ->select("id", "name", "email")
    ->from("users")
    ->where("age > 18")
    ->build(); // Result: "SELECT id, name, email FROM users WHERE age > 18"
```

In the above example, the `SqlQueryBuilder` class provides a fluent interface for building SQL queries. The `select`, `from`, and `where` methods add columns, table name, and WHERE clauses to the query builder, respectively. The `build` method returns the final SQL query as a string.

These are just simple examples of how you can use the Fluent Interface Design Pattern to create a DSL. The possibilities are endless, and you can create DSLs for various domains, including configuration files, HTML, XML, JSON, and more.

Here are more complex and advanced examples of using the Fluent Interface Design Pattern in PHP:

<u>Example 4: Database Query Builder
</u>
Suppose you want to create a fluent database query builder that supports various query operations like SELECT, INSERT, UPDATE, and DELETE. Here's an example of how you can implement it:

```php
class QueryBuilder
{
    protected $table;
    protected $columns = [];
    protected $where = [];
    protected $values = [];

    public function table($table)
    {
        $this->table = $table;
        return $this;
    }

    public function select(...$columns)
    {
        $this->columns = array_merge($this->columns, $columns);
        return $this;
    }

    public function where($column, $operator, $value)
    {
        $this->where[] = compact('column', 'operator', 'value');
        return $this;
    }

    public function insert(array $values)
    {
        $this->values = $values;
        return $this;
    }

    public function update(array $values)
    {
        $this->values = $values;
        return $this;
    }

    public function delete()
    {
        return $this;
    }

    public function build()
    {
        $query = '';

        if (!empty($this->columns)) {
            $query .= 'SELECT ' . implode(', ', $this->columns) . ' FROM ' . $this->table;
        } elseif (!empty($this->values)) {
            if ($this->table) {
                $query .= 'INSERT INTO ' . $this->table . ' SET ';
            } else {
                $query .= 'UPDATE SET ';
            }

            $values = [];
            foreach ($this->values as $column => $value) {
                $values[] = $column . ' = ' . $value;
            }

            $query .= implode(', ', $values);
        } else {
            $query .= 'DELETE FROM ' . $this->table;
        }

        if (!empty($this->where)) {
            $query .= ' WHERE ';

            $conditions = [];
            foreach ($this->where as $clause) {
                $conditions[] = $clause['column'] . ' ' . $clause['operator'] . ' ' . $clause['value'];
            }

            $query .= implode(' AND ', $conditions);
        }

        return $query;
    }
}

// Example usage
$query = (new QueryBuilder())
    ->table('users')
    ->select('name', 'email')
    ->where('age', '>', 18)
    ->build();

echo $query; // Output: SELECT name, email FROM users WHERE age > 18
```

In this example, the `QueryBuilder` class supports building SELECT, INSERT, UPDATE, and DELETE queries. The methods `select`, `where`, `insert`, and `update` set the desired query components, and the `build` method constructs the final query string.

<u>Example 5: Fluent API for Configuration
</u>
Suppose you want to create a fluent API for configuring various settings in your application. Here's an example:

```php
class AppConfigurator
{
    protected $settings = [];

    public function setDatabaseConfig($host, $username, $password, $database)
    {
        $this->settings['database'] = compact('host', 'username', 'password', 'database');
        return $this;
    }

    public function setCacheConfig($driver, $host, $port)
    {
        $this->settings['cache'] = compact('driver', 'host', 'port');
        return $this;
    }

    public function setLoggingConfig($

enabled, $logLevel)
    {
        $this->settings['logging'] = compact('enabled', 'logLevel');
        return $this;
    }

    public function build()
    {
        return $this->settings;
    }
}

// Example usage
$config = (new AppConfigurator())
    ->setDatabaseConfig('localhost', 'root', 'password', 'my_database')
    ->setCacheConfig('redis', '127.0.0.1', 6379)
    ->setLoggingConfig(true, 'debug')
    ->build();

print_r($config);
```

In this example, the `AppConfigurator` class provides fluent methods for setting different configuration options such as the database, cache, and logging settings. The `build` method returns the final configuration as an array.

<u>Example 6: Fluent Builder for Object Creation
</u>
Suppose you have a complex object with many properties and want to simplify the process of creating instances of that object. Here's an example:

```php
class Car
{
    protected $brand;
    protected $model;
    protected $color;
    protected $year;

    public function setBrand($brand)
    {
        $this->brand = $brand;
        return $this;
    }

    public function setModel($model)
    {
        $this->model = $model;
        return $this;
    }

    public function setColor($color)
    {
        $this->color = $color;
        return $this;
    }

    public function setYear($year)
    {
        $this->year = $year;
        return $this;
    }

    public function build()
    {
        return new Car($this->brand, $this->model, $this->color, $this->year);
    }
}

// Example usage
$car = (new Car())
    ->setBrand('Toyota')
    ->setModel('Camry')
    ->setColor('Blue')
    ->setYear(2022)
    ->build();

echo $car->getBrand(); // Output: Toyota
echo $car->getModel(); // Output: Camry
echo $car->getColor(); // Output: Blue
echo $car->getYear(); // Output: 2022
```

In this example, the `Car` class has fluent methods for setting the brand, model, color, and year of a car. The `build` method creates an instance of the `Car` object with the specified properties.

These examples demonstrate how the Fluent Interface Design Pattern can be used in more complex scenarios, such as building database queries, configuring applications, and simplifying object creation.

## Conclusion

In conclusion, the Fluent Interface Design Pattern is a powerful and elegant design pattern that simplifies API usage by allowing method chaining and creating a natural language-like interface. By using the Fluent Interface Design Pattern, developers can write clean, readable, and highly expressive code in PHP, Laravel, and beyond.

The benefits of using the Fluent Interface Design Pattern are numerous. It enhances code readability and intuitiveness, making it easier to understand and maintain. The ability to chain methods together in a single statement reduces errors and provides flexibility in configuring objects and invoking methods. Additionally, the Fluent Interface Design Pattern can be used to create domain-specific languages, allowing developers to build expressive APIs tailored to specific domains.

In the provided examples, we saw how the Fluent Interface Design Pattern can be applied to set properties, invoke methods, and create domain-specific languages. From building SQL queries to performing calculations and configuring application settings, the Fluent Interface Design Pattern proves to be a versatile and valuable tool in software development. By leveraging this pattern, developers can write more expressive and efficient code, enhancing their productivity and the overall quality of their applications.

Furthermore, the Fluent Interface Design Pattern encourages good design practices such as encapsulation, modularity, and separation of concerns. It promotes the creation of reusable and composable code, allowing for flexible and extensible implementations.

Overall, the Fluent Interface Design Pattern is a valuable addition to any developer's toolkit. It brings clarity, expressiveness, and flexibility to code, resulting in code that is more maintainable, readable, and enjoyable to work with. By leveraging the power of method chaining and a fluent API, developers can create elegant and concise code that is both efficient and easy to understand.