CompositeExpression.php 3.47 KB
Newer Older
1 2 3 4
<?php

namespace Doctrine\DBAL\Query\Expression;

5
use Countable;
6
use function array_merge;
7 8 9
use function count;
use function implode;

10 11 12
/**
 * Composite expression is responsible to build a group of similar expression.
 */
13
class CompositeExpression implements Countable
14 15
{
    /**
Benjamin Morel's avatar
Benjamin Morel committed
16
     * Constant that represents an AND composite expression.
17
     */
18
    public const TYPE_AND = 'AND';
19

20
    /**
Benjamin Morel's avatar
Benjamin Morel committed
21
     * Constant that represents an OR composite expression.
22
     */
23
    public const TYPE_OR = 'OR';
24

25
    /**
Benjamin Morel's avatar
Benjamin Morel committed
26 27 28
     * The instance type of composite expression.
     *
     * @var string
29 30
     */
    private $type;
31

32
    /**
Benjamin Morel's avatar
Benjamin Morel committed
33 34
     * Each expression part of the composite expression.
     *
35
     * @var self[]|string[]
36
     */
37
    private $parts = [];
38

39
    /**
40 41
     * @internal Use the and() / or() factory methods.
     *
42 43
     * @param string          $type  Instance type of composite expression.
     * @param self[]|string[] $parts Composition of expressions to be joined on composite expression.
44
     */
45
    public function __construct($type, array $parts = [])
46 47
    {
        $this->type = $type;
48

49 50
        $this->addMultiple($parts);
    }
51

52 53 54 55
    /**
     * @param self|string $part
     * @param self|string ...$parts
     */
56 57 58 59 60
    public static function and($part, ...$parts) : self
    {
        return new self(self::TYPE_AND, array_merge([$part], $parts));
    }

61 62 63 64
    /**
     * @param self|string $part
     * @param self|string ...$parts
     */
65 66 67 68 69
    public static function or($part, ...$parts) : self
    {
        return new self(self::TYPE_OR, array_merge([$part], $parts));
    }

70 71
    /**
     * Adds multiple parts to composite expression.
72
     *
73 74
     * @deprecated This class will be made immutable. Use with() instead.
     *
75
     * @param self[]|string[] $parts
76
     *
Grégoire Paris's avatar
Grégoire Paris committed
77
     * @return CompositeExpression
78
     */
79
    public function addMultiple(array $parts = [])
80
    {
81
        foreach ($parts as $part) {
82 83
            $this->add($part);
        }
84

85 86
        return $this;
    }
87

88 89
    /**
     * Adds an expression to composite expression.
90
     *
91 92
     * @deprecated This class will be made immutable. Use with() instead.
     *
93
     * @param mixed $part
Benjamin Morel's avatar
Benjamin Morel committed
94
     *
Grégoire Paris's avatar
Grégoire Paris committed
95
     * @return CompositeExpression
96 97 98
     */
    public function add($part)
    {
99 100
        if (empty($part)) {
            return $this;
101
        }
102

103
        if ($part instanceof self && count($part) === 0) {
104 105 106 107 108
            return $this;
        }

        $this->parts[] = $part;

109 110
        return $this;
    }
111

112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
    /**
     * Returns a new CompositeExpression with the given parts added.
     *
     * @param self|string $part
     * @param self|string ...$parts
     */
    public function with($part, ...$parts) : self
    {
        $that = clone $this;

        $that->parts[] = $part;

        foreach ($parts as $part) {
            $that->parts[] = $part;
        }

        return $that;
    }

131 132
    /**
     * Retrieves the amount of expressions on composite expression.
133
     *
134
     * @return int
135 136 137 138 139
     */
    public function count()
    {
        return count($this->parts);
    }
140

141
    /**
Benjamin Morel's avatar
Benjamin Morel committed
142
     * Retrieves the string representation of this composite expression.
143
     *
144 145 146 147
     * @return string
     */
    public function __toString()
    {
148
        if ($this->count() === 1) {
149 150
            return (string) $this->parts[0];
        }
151

152 153
        return '(' . implode(') ' . $this->type . ' (', $this->parts) . ')';
    }
154

155
    /**
Benjamin Morel's avatar
Benjamin Morel committed
156
     * Returns the type of this composite expression (AND/OR).
157
     *
158 159 160 161 162 163
     * @return string
     */
    public function getType()
    {
        return $this->type;
    }
Benjamin Eberlei's avatar
Benjamin Eberlei committed
164
}