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