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\Protocol\Factory;
12
13use FreeDSx\Asn1\Type\AbstractType;
14use FreeDSx\Ldap\Exception\InvalidArgumentException;
15use FreeDSx\Ldap\Exception\ProtocolException;
16use FreeDSx\Ldap\Exception\RuntimeException;
17use FreeDSx\Ldap\Search\Filter\AndFilter;
18use FreeDSx\Ldap\Search\Filter\ApproximateFilter;
19use FreeDSx\Ldap\Search\Filter\EqualityFilter;
20use FreeDSx\Ldap\Search\Filter\FilterInterface;
21use FreeDSx\Ldap\Search\Filter\GreaterThanOrEqualFilter;
22use FreeDSx\Ldap\Search\Filter\LessThanOrEqualFilter;
23use FreeDSx\Ldap\Search\Filter\MatchingRuleFilter;
24use FreeDSx\Ldap\Search\Filter\NotFilter;
25use FreeDSx\Ldap\Search\Filter\OrFilter;
26use FreeDSx\Ldap\Search\Filter\PresentFilter;
27use FreeDSx\Ldap\Search\Filter\SubstringFilter;
28
29/**
30 * Get the filter object from a specific ASN1 tag type.
31 *
32 * @author Chad Sikorra <Chad.Sikorra@gmail.com>
33 */
34class FilterFactory
35{
36    /**
37     * @var array
38     */
39    protected static $map = [
40        0 => AndFilter::class,
41        1 => OrFilter::class,
42        2 => NotFilter::class,
43        3 => EqualityFilter::class,
44        4 => SubstringFilter::class,
45        5 => GreaterThanOrEqualFilter::class,
46        6 => LessThanOrEqualFilter::class,
47        7 => PresentFilter::class,
48        8 => ApproximateFilter::class,
49        9 => MatchingRuleFilter::class,
50    ];
51
52    /**
53     * @throws ProtocolException
54     */
55    public static function get(AbstractType $type): FilterInterface
56    {
57        $filterClass = self::$map[$type->getTagNumber()] ?? null;
58        if ($filterClass === null) {
59            throw new ProtocolException(sprintf(
60                'The received filter "%s" is not recognized.',
61                $type->getTagNumber()
62            ));
63        }
64        $filterConstruct = $filterClass . '::fromAsn1';
65        if (!is_callable($filterConstruct)) {
66            throw new RuntimeException(sprintf(
67                'The filter construct is not callable: %s',
68                $filterConstruct
69            ));
70        }
71
72        return call_user_func($filterConstruct, $type);
73    }
74
75    /**
76     * @param int $filterType
77     * @return bool
78     */
79    public static function has(int $filterType): bool
80    {
81        return isset(self::$map[$filterType]);
82    }
83
84    /**
85     * @param int $filterType
86     * @param string $filterClass
87     */
88    public static function set(int $filterType, string $filterClass): void
89    {
90        if (!class_exists($filterClass)) {
91            throw new InvalidArgumentException(sprintf('The filter class does not exist: %s', $filterClass));
92        }
93        if (!is_subclass_of($filterClass, FilterInterface::class)) {
94            throw new InvalidArgumentException(sprintf('The filter class must implement FilterInterface: %s', $filterClass));
95        }
96
97        self::$map[$filterType] = $filterClass;
98    }
99}
100