1<?php
2namespace Aws;
3
4use Psr\Http\Message\RequestInterface;
5use Aws\Exception\AwsException;
6
7/**
8 * Represents a history container that is required when using the history
9 * middleware.
10 */
11class History implements \Countable, \IteratorAggregate
12{
13    private $maxEntries;
14    private $entries = array();
15
16    /**
17     * @param int $maxEntries Maximum number of entries to store.
18     */
19    public function __construct($maxEntries = 10)
20    {
21        $this->maxEntries = $maxEntries;
22    }
23
24    public function count()
25    {
26        return count($this->entries);
27    }
28
29    public function getIterator()
30    {
31        return new \ArrayIterator(array_values($this->entries));
32    }
33
34    /**
35     * Get the last finished command seen by the history container.
36     *
37     * @return CommandInterface
38     * @throws \LogicException if no commands have been seen.
39     */
40    public function getLastCommand()
41    {
42        if (!$this->entries) {
43            throw new \LogicException('No commands received');
44        }
45
46        return end($this->entries)['command'];
47    }
48
49    /**
50     * Get the last finished request seen by the history container.
51     *
52     * @return RequestInterface
53     * @throws \LogicException if no requests have been seen.
54     */
55    public function getLastRequest()
56    {
57        if (!$this->entries) {
58            throw new \LogicException('No requests received');
59        }
60
61        return end($this->entries)['request'];
62    }
63
64    /**
65     * Get the last received result or exception.
66     *
67     * @return ResultInterface|AwsException
68     * @throws \LogicException if no return values have been received.
69     */
70    public function getLastReturn()
71    {
72        if (!$this->entries) {
73            throw new \LogicException('No entries');
74        }
75
76        $last = end($this->entries);
77
78        if (isset($last['result'])) {
79            return $last['result'];
80        }
81
82        if (isset($last['exception'])) {
83            return $last['exception'];
84        }
85
86        throw new \LogicException('No return value for last entry.');
87    }
88
89    /**
90     * Initiate an entry being added to the history.
91     *
92     * @param CommandInterface $cmd Command be executed.
93     * @param RequestInterface $req Request being sent.
94     *
95     * @return string Returns the ticket used to finish the entry.
96     */
97    public function start(CommandInterface $cmd, RequestInterface $req)
98    {
99        $ticket = uniqid();
100        $this->entries[$ticket] = [
101            'command'   => $cmd,
102            'request'   => $req,
103            'result'    => null,
104            'exception' => null,
105        ];
106
107        return $ticket;
108    }
109
110    /**
111     * Finish adding an entry to the history container.
112     *
113     * @param string $ticket Ticket returned from the start call.
114     * @param mixed  $result The result (an exception or AwsResult).
115     */
116    public function finish($ticket, $result)
117    {
118        if (!isset($this->entries[$ticket])) {
119            throw new \InvalidArgumentException('Invalid history ticket');
120        }
121
122        if (isset($this->entries[$ticket]['result'])
123            || isset($this->entries[$ticket]['exception'])
124        ) {
125            throw new \LogicException('History entry is already finished');
126        }
127
128        if ($result instanceof \Exception) {
129            $this->entries[$ticket]['exception'] = $result;
130        } else {
131            $this->entries[$ticket]['result'] = $result;
132        }
133
134        if (count($this->entries) >= $this->maxEntries) {
135            $this->entries = array_slice($this->entries, -$this->maxEntries, null, true);
136        }
137    }
138
139    /**
140     * Flush the history
141     */
142    public function clear()
143    {
144        $this->entries = [];
145    }
146
147    /**
148     * Converts the history to an array.
149     *
150     * @return array
151     */
152    public function toArray()
153    {
154        return array_values($this->entries);
155    }
156}
157