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\Operation\Request\ExtendedRequest;
19use FreeDSx\Ldap\Operation\Response\ExtendedResponse;
20use FreeDSx\Ldap\Operation\Response\PasswordModifyResponse;
21
22/**
23 * Used to instantiate specific extended response OIDs.
24 *
25 * @author Chad Sikorra <Chad.Sikorra@gmail.com>
26 */
27class ExtendedResponseFactory
28{
29    /**
30     * @var string[]
31     */
32    protected static $map = [
33        ExtendedRequest::OID_PWD_MODIFY => PasswordModifyResponse::class,
34    ];
35
36    /**
37     * Retrieve the Request Response/Request class given a protocol number and the ASN1.
38     *
39     * @param AbstractType $asn1
40     * @param string $oid
41     * @return ExtendedResponse
42     * @throws ProtocolException
43     * @throws RuntimeException
44     */
45    public function get(AbstractType $asn1, string $oid): ExtendedResponse
46    {
47        if (!self::has($oid)) {
48            throw new ProtocolException(sprintf(
49                'There is no extended response mapped for %s.',
50                $oid
51            ));
52        }
53        $responseConstruct = self::$map[$oid] . '::fromAsn1';
54        if (!is_callable($responseConstruct)) {
55            throw new RuntimeException(sprintf(
56                'The extended response construct is not callable: %s',
57                $responseConstruct
58            ));
59        }
60
61        return call_user_func($responseConstruct, $asn1);
62    }
63
64    /**
65     * Check whether a specific control OID is mapped to a class.
66     *
67     * @param string $oid
68     * @return bool
69     */
70    public function has(string $oid)
71    {
72        return isset(self::$map[$oid]);
73    }
74
75    /**
76     * Set a specific class for an operation. It must implement ProtocolElementInterface.
77     *
78     * @throws InvalidArgumentException
79     */
80    public static function set(string $oid, string $className): void
81    {
82        if (!class_exists($className)) {
83            throw new InvalidArgumentException(sprintf(
84                'The class for the extended response %s does not exist: %s',
85                $oid,
86                $className
87            ));
88        }
89        if (!is_subclass_of($className, ExtendedResponse::class)) {
90            throw new InvalidArgumentException(sprintf(
91                'The class must extend the ExtendedResponse, but it does not: %s',
92                $className
93            ));
94        }
95        self::$map[$oid] = $className;
96    }
97}
98