1<?php
2/**
3 * This file is part of the FreeDSx LDAP package.
4 *
5 * (c) Chad Sikorra <Chad.Sikorra@gmail.com>
6 *
7 * For the full copyright and license information, please view the LICENSE
8 * file that was distributed with this source code.
9 */
10
11namespace FreeDSx\Ldap\Search\Filter;
12
13use FreeDSx\Asn1\Asn1;
14use FreeDSx\Asn1\Type\AbstractType;
15use FreeDSx\Asn1\Type\IncompleteType;
16use FreeDSx\Asn1\Type\SetType;
17use FreeDSx\Ldap\Exception\ProtocolException;
18use FreeDSx\Ldap\Protocol\Factory\FilterFactory;
19use FreeDSx\Ldap\Protocol\LdapEncoder;
20
21/**
22 * Methods needed to implement the filter container interface.
23 *
24 * @author Chad Sikorra <Chad.Sikorra@gmail.com>
25 */
26trait FilterContainerTrait
27{
28    /**
29     * @var FilterInterface[]
30     */
31    protected $filters = [];
32
33    /**
34     * @param FilterInterface[] ...$filters
35     */
36    public function __construct(FilterInterface ...$filters)
37    {
38        $this->filters = $filters;
39    }
40
41    /**
42     * @param FilterInterface[] ...$filters
43     * @return $this
44     */
45    public function add(FilterInterface ...$filters)
46    {
47        foreach ($filters as $filter) {
48            $this->filters[] = $filter;
49        }
50
51        return $this;
52    }
53
54    /**
55     * @param FilterInterface $filter
56     * @return bool
57     */
58    public function has(FilterInterface $filter): bool
59    {
60        return array_search($filter, $this->filters, true) !== false;
61    }
62
63    /**
64     * @param FilterInterface[] ...$filters
65     * @return $this
66     */
67    public function remove(FilterInterface ...$filters)
68    {
69        foreach ($filters as $filter) {
70            if (($i = array_search($filter, $this->filters, true)) !== false) {
71                unset($this->filters[$i]);
72            }
73        }
74
75        return $this;
76    }
77
78    /**
79     * @param FilterInterface[] ...$filters
80     * @return $this
81     */
82    public function set(FilterInterface ...$filters)
83    {
84        $this->filters = $filters;
85
86        return $this;
87    }
88
89    /**
90     * @return FilterInterface[]
91     */
92    public function get(): array
93    {
94        return $this->filters;
95    }
96
97    /**
98     * {@inheritdoc}
99     */
100    public function toAsn1(): AbstractType
101    {
102        return Asn1::context(self::CHOICE_TAG, Asn1::setOf(
103            ...array_map(function ($filter) {
104                /** @var FilterInterface $filter */
105                return $filter->toAsn1();
106            }, $this->filters)
107        ));
108    }
109
110    /**
111     * {@inheritdoc}
112     */
113    public function toString(): string
114    {
115        return self::PAREN_LEFT
116            . self::FILTER_OPERATOR
117            . implode('', array_map(function ($filter) {
118                /** @var FilterInterface $filter */
119                return $filter->toString();
120            }, $this->filters))
121            . self::PAREN_RIGHT;
122    }
123
124    /**
125     * @return \ArrayIterator
126     */
127    public function getIterator()
128    {
129        return new \ArrayIterator($this->filters);
130    }
131
132    /**
133     * @return int
134     */
135    public function count()
136    {
137        return count($this->filters);
138    }
139
140    /**
141     * @return string
142     */
143    public function __toString()
144    {
145        return $this->toString();
146    }
147
148    /**
149     * {@inheritdoc}
150     */
151    public static function fromAsn1(AbstractType $type)
152    {
153        $type = $type instanceof IncompleteType ? (new LdapEncoder())->complete($type, AbstractType::TAG_TYPE_SET) : $type;
154        if (!($type instanceof SetType)) {
155            throw new ProtocolException('The filter is malformed');
156        }
157
158        $filters = [];
159        foreach ($type->getChildren() as $child) {
160            $filters[] = FilterFactory::get($child);
161        }
162
163        return new self(...$filters);
164    }
165}
166