2.8. Fluent Interface

2.8.1. Purpose

To write code that is easy readable just like sentences in a naturallanguage (like English).

2.8.2. Examples

  • Doctrine2’s QueryBuilder works something like that example classbelow
  • PHPUnit uses fluent interfaces to build mock objects
  • Yii Framework: CDbCommand and CActiveRecord use this pattern, too

2.8.3. UML Diagram

Alt FluentInterface UML Diagram

2.8.4. Code

You can also find this code on GitHub

Sql.php

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

2.8.5. Test

Tests/FluentInterfaceTest.php

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