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