2.8. Текучий Интерфейс (Fluent Interface)

2.8.1. Назначение

Писать код, который легко читается, как предложения в естественном языке (вроде русского или английского).

2.8.2. Примеры

  • Doctrine2’s QueryBuilder работает примерно также, как пример ниже.

  • PHPUnit использует текучий интерфейс, чтобы создавать макеты объектов.

2.8.3. Диаграмма UML

Alt FluentInterface UML Diagram

2.8.4. Код

Вы можете найти этот код на GitHub

Sql.php

 1<?php
 2
 3declare(strict_types=1);
 4
 5namespace DesignPatterns\Structural\FluentInterface;
 6
 7class Sql implements \Stringable
 8{
 9    private array $fields = [];
10    private array $from = [];
11    private array $where = [];
12
13    public function select(array $fields): Sql
14    {
15        $this->fields = $fields;
16
17        return $this;
18    }
19
20    public function from(string $table, string $alias): Sql
21    {
22        $this->from[] = $table . ' AS ' . $alias;
23
24        return $this;
25    }
26
27    public function where(string $condition): Sql
28    {
29        $this->where[] = $condition;
30
31        return $this;
32    }
33
34    public function __toString(): string
35    {
36        return sprintf(
37            'SELECT %s FROM %s WHERE %s',
38            join(', ', $this->fields),
39            join(', ', $this->from),
40            join(' AND ', $this->where)
41        );
42    }
43}

2.8.5. Тест

Tests/FluentInterfaceTest.php

 1<?php
 2
 3declare(strict_types=1);
 4
 5namespace DesignPatterns\Structural\FluentInterface\Tests;
 6
 7use DesignPatterns\Structural\FluentInterface\Sql;
 8use PHPUnit\Framework\TestCase;
 9
10class FluentInterfaceTest extends TestCase
11{
12    public function testBuildSQL()
13    {
14        $query = (new Sql())
15                ->select(['foo', 'bar'])
16                ->from('foobar', 'f')
17                ->where('f.bar = ?');
18
19        $this->assertSame('SELECT foo, bar FROM foobar AS f WHERE f.bar = ?', (string) $query);
20    }
21}