Passed
Pull Request — master (#29)
by
unknown
02:05
created

DelegatingTicketStore::getTicket()   B

Complexity

Conditions 7
Paths 12

Size

Total Lines 25
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
eloc 18
c 1
b 0
f 0
nc 12
nop 1
dl 0
loc 25
rs 8.8333
1
<?php
2
3
namespace SimpleSAML\Module\casserver\Cas\Ticket;
4
5
use InvalidArgumentException;
6
use SimpleSAML\Configuration;
7
use SimpleSAML\Logger;
8
use SimpleSAML\Module;
9
10
/**
11
 * Ticket store that delegates to other ticket stores.
12
 * Allows you to use multiple source for redundancy or allows a transition from one source to another.
13
 */
14
class DelegatingTicketStore extends TicketStore
15
{
16
    /**
17
     * @var string Delegate to 'all', 'first', or a named entry.
18
     */
19
    private $delegateTo = 'all';
20
21
    /**
22
     * @var TicketStore[]
23
     */
24
    private $ticketStores = [];
25
26
    /**
27
     * @var TicketStore
28
     */
29
    private $primaryDelegate;
30
31
    /**
32
     * @param \SimpleSAML\Configuration $casConfig The cas configuration.
33
     */
34
    public function __construct(Configuration $casConfig)
35
    {
36
        $config = $casConfig->getConfigItem('ticketstore');
37
        $this->delegateTo = $config->getString('delegateTo', 'all');
38
        /** @var $storeConfig Configuration */
39
        foreach ($config->getArray('ticketStores') as $name => $storeArray) {
40
            // TicketStore expects the store config to be in a specific item
41
            $storeConfig = Configuration::loadFromArray(['ticketstore' => $storeArray]);
42
            $class = $storeConfig->getConfigItem('ticketstore')->getString('class');
43
            $ticketStoreClass = Module::resolveClass($class, 'Cas_Ticket');
44
            try {
45
                $ticketStore = new $ticketStoreClass($storeConfig);
46
                $ticketStores[$name] = $ticketStore;
47
            } catch (\Exception $e) {
48
                Logger::error("Unable to create ticket store '$name'. Error " . $e->getMessage());
49
            }
50
        }
51
        assert(!empty($ticketStores));
52
        $this->ticketStores = $ticketStores;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $ticketStores seems to be defined by a foreach iteration on line 39. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
53
54
        if ($this->delegateTo === 'first') {
55
            $this->primaryDelegate = reset($ticketStores);
56
        } elseif ($this->delegateTo !== 'all') {
57
            if (array_key_exists($this->delegateTo, $ticketStores)) {
58
                $this->primaryDelegate = $ticketStores[$this->delegateTo];
59
            } else {
60
                throw new InvalidArgumentException("No ticket store called '" . $this->delegateTo . "'");
61
            }
62
        }
63
    }
64
65
    /**
66
     * Get the ticket, searching one or all of the delegates
67
     * @param string $ticketId The ticket to find
68
     * @return array|null The ticket or null if none found
69
     * @throws \Exception from any delegate stores ONLY if no delegates worked
70
     */
71
    public function getTicket($ticketId)
72
    {
73
        if ($this->delegateTo === 'all') {
74
            $ticket = null;
75
            $rethrowException = null;
76
            foreach ($this->ticketStores as $name => $store) {
77
                try {
78
                    $ticket = $store->getTicket($ticketId);
79
                    $rethrowException = false; // no need to rethrow, at least one store worked
80
                } catch (\Exception $e) {
81
                    if ($rethrowException === null) {
82
                        $rethrowException = $e;
83
                    }
84
                    Logger::error("Unable to read tickets from '$name'. Trying next store. Error " . $e->getMessage());
85
                }
86
                if ($ticket) {
87
                    return $ticket;
88
                }
89
            }
90
            if ($rethrowException) {
91
                throw $rethrowException;
92
            }
93
            return $ticket;
94
        } else {
95
            return $this->primaryDelegate->getTicket($ticketId);
96
        }
97
    }
98
99
    /**
100
     * @param array $ticket Ticket to add
101
     * @throws \Exception from any delegate stores ONLY if no delegates worked
102
     */
103
    public function addTicket(array $ticket)
104
    {
105
        if ($this->delegateTo === 'all') {
106
            $rethrowException = null;
107
            foreach ($this->ticketStores as $name => $store) {
108
                try {
109
                    $store->addTicket($ticket);
110
                    $rethrowException = false; // no need to rethrow, at least one store worked
111
                } catch (\Exception $e) {
112
                    if ($rethrowException === null) {
113
                        $rethrowException = $e;
114
                    }
115
                    Logger::error("Unable to add ticket to '$name'. Continue to next store. Error" . $e->getMessage());
116
                }
117
            }
118
            if ($rethrowException) {
119
                throw $rethrowException;
120
            }
121
        } else {
122
            $this->primaryDelegate->addTicket($ticket);
123
        }
124
    }
125
126
    /**
127
     * @param string $ticketId Ticket to delete
128
     */
129
    public function deleteTicket($ticketId)
130
    {
131
        if ($this->delegateTo === 'all') {
132
            foreach ($this->ticketStores as $name => $store) {
133
                try {
134
                    $store->deleteTicket($ticketId);
135
                } catch (\Exception $e) {
136
                    Logger::error("Unable to delete ticket from '$name'. Trying next store. Error" . $e->getMessage());
137
                }
138
            }
139
        } else {
140
            $this->primaryDelegate->deleteTicket($ticketId);
141
        }
142
    }
143
}
144