Completed
Pull Request — master (#30)
by Bernhard
03:34 queued 02:04
created

File::getStorageContent()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 2
cp 0
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 2
1
<?php
2
3
/**
4
 * \Wicked\Timely\Storage\File
5
 *
6
 * NOTICE OF LICENSE
7
 *
8
 * This source file is subject to the Open Software License (OSL 3.0)
9
 * that is available through the world-wide-web at this URL:
10
 * http://opensource.org/licenses/osl-3.0.php
11
 *
12
 * PHP version 5
13
 *
14
 * @author    wick-ed
15
 * @copyright 2016 Bernhard Wick
16
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
17
 * @link      https://github.com/wick-ed/timely
18
 */
19
20
namespace Wicked\Timely\Storage;
21
22
use Wicked\Timely\Entities\Booking;
23
use Wicked\Timely\Entities\Clipping;
24
use Wicked\Timely\Formatter\FormatterFactory;
25
use Wicked\Timely\Entities\BookingFactory;
26
27
/**
28
 * File storage
29
 *
30
 * @author    wick-ed
31
 * @copyright 2016 Bernhard Wick
32
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
33
 * @link      https://github.com/wick-ed/timely
34
 */
35
class File implements StorageInterface
36
{
37
38
    /**
39
     * Default character for a line break in the format
40
     *
41
     * @var string LINE_BREAK
42
     */
43
    const LINE_BREAK = ';';
44
45
    /**
46
     * Default character sequence for segment separation
47
     *
48
     * @var string SEPARATOR
49
     */
50
    const SEPARATOR = ' | ';
51
52
    /**
53
     * Name of the log file
54
     *
55
     * @var string DATA_NAME
56
     */
57
    const DATA_NAME = 'timely-log.txt';
58
59
    /**
60
     * Path to the log file
61
     *
62
     * @var string $logFilePath
63
     */
64
    protected $logFilePath;
65
66
    /**
67
     * Save the last retrieve from file
68
     *
69
     * @var string
70
     */
71
    protected $lastRetrieve;
72
73
    /**
74
     * Default constructor
75
     */
76 4
    public function __construct()
77
    {
78
        // calculate the default file path
79 4
        $this->logFilePath = dirname(dirname(__DIR__)) . DIRECTORY_SEPARATOR . 'data' . DIRECTORY_SEPARATOR . self::DATA_NAME;
80
        // check if the file exists, if not create it
81 4
        if (!is_file($this->logFilePath)) {
82 1
            touch($this->logFilePath);
83
        }
84 4
    }
85
86
    /**
87
     * Getter for the log file path
88
     *
89
     * @return string
90
     */
91
    public function getLogFilePath()
92
    {
93
        return $this->logFilePath;
94
    }
95
96
    /**
97
     * Stores a single booking
98
     *
99
     * @param \Wicked\Timely\Entities\Booking $booking The booking to store
100
     *
101
     * @return void
102
     */
103
    public function store(Booking $booking)
104
    {
105
        // get the formatter and convert to string
106
        $formatter = FormatterFactory::getFormatter();
107
        $bookString = $formatter->toString($booking);
108
109
        // write the new booking to the beginning of the file
110
        $this->storeNewestStorageContent($bookString);
111
    }
112
113
    /**
114
     * Stores a single booking that pushed
115
     *
116
     * @param \Wicked\Timely\Entities\Booking $booking The booking to store
117
     *
118
     * @return void
119
     */
120
    public function storePush(Booking $booking)
121
    {
122
        // get the formatter and convert to string
123
        $formatter = FormatterFactory::getFormatter();
124
        $bookString = $formatter->toString($booking);
125
        $booking->setPushed(true);
126
        $bookStringPushed = $formatter->toString($booking);
127
128
        $content = $this->getStorageContent();
129
        // replace the origin booking with the pushed
130
        $content = str_replace($bookString, $bookStringPushed, $content);
131
        $path = $this->getLogFilePath();
132
        file_put_contents($path, $content);
133
    }
134
135
    /**
136
     * Get the content of the files storage
137
     *
138
     * @param string $bookString content to store
139
     *
140
     * @return void
141
     */
142
    protected function storeNewestStorageContent($bookString)
143
    {
144
        $path = $this->getLogFilePath();
145
        file_put_contents($path, $bookString . $this->getStorageContent());
146
    }
147
148
    /**
149
     * Get the content of the files storage
150
     *
151
     * @return string
152
     */
153
    protected function getStorageContent()
154
    {
155
        return file_get_contents($this->getLogFilePath());
156
    }
157
158
    /**
159
     * Retrieves retrieves the last booking from the storage
160
     *
161
     * @param boolean $includeMetaTickets Whether or not the retrieved booking can be a meta ticket
162
     *
163
     * @return \Wicked\Timely\Entities\Booking
164
     */
165
    public function retrieveLast($includeMetaTickets = false)
166
    {
167
        $tmp = $this->retrieve(null, null, null, 1, true, $includeMetaTickets);
168
        return array_pop($tmp);
169
    }
170
171
    /**
172
     * Retrieves one or several bookings from the storage. Bookings can be filtered by pattern,
173
     * date, etc.
174
     *
175
     * @param null|string  $pattern   A pattern to filter ticket IDs for. Defaults to NULL
176
     * @param null|integer $toDate    Date up to which bookings will be returned. Defaults to NULL
177
     * @param null|integer $fromDate  Date from which on bookings will be returned. Defaults to NULL
178
     * @param null|integer $limit     Number of non-meta bookings the retrieval is limited to. Defaults to NULL
179
     * @param boolean      $dontClip  Whether or not the retrieved bookings should be clipped where appropriate. Defaults to FALSE
180
     * @param boolean      $countMeta Whether or not meta tickets will be included in the counter which is used for our limit
181
     *
182
     * @return \Wicked\Timely\Entities\Booking[]
183
     */
184 4
    public function retrieve($pattern = null, $toDate = null, $fromDate = null, $limit = null, $dontClip = false, $countMeta = false)
185
    {
186
        // test if we got a pattern, if not match against all
187 4
        if (is_null($pattern)) {
188 4
            $pattern = '*';
189
        }
190
        // test if we got some dates to filter by
191 4
        if (is_null($toDate)) {
192 4
            $toDate = 9999999999;
193
        }
194 4
        if (is_null($fromDate)) {
195 2
            $fromDate = 0;
196
        }
197
198
        // get the raw entries
199 4
        $this->lastRetrieve = $this->getStorageContent();
200 4
        $rawEntries = explode(self::LINE_BREAK, rtrim($this->lastRetrieve, self::LINE_BREAK));
201
202 4
        $entries = array();
203
204
        // iterate them and generate the entities
205 4
        $bookingKey = null;
206 4
        $bookingCount = 0;
207 4
        foreach ($rawEntries as $key => $rawEntry) {
208
            // get the potential entry and filter them by ticket ID
209 4
            $entry = explode(self::SEPARATOR, trim($rawEntry, ' |'));
210 4
            $timestamp = strtotime($entry[0]);
211 4
            if (isset($entry[1]) &&
212 4
                (fnmatch($pattern, $entry[1]) || isset(BookingFactory::getAllMetaTicketIds()[$entry[1]])) &&
213 4
                $timestamp > $fromDate && $timestamp < $toDate
214
            ) {
215
                // collect the actual booking
216 4
                $comment = isset($entry[2]) ? $entry[2] : '';
217 4
                $pushed = isset($entry[3]) && !empty($entry[3]) ? true : false;
218 4
                $booking = BookingFactory::getBooking($comment, $entry[1], $entry[0], $pushed);
219 4
                $entries[] = $booking;
220
221
                // increase the booking counter
222 4
                if (!$booking->isMetaBooking() || $countMeta) {
223 4
                    $bookingCount ++;
224
                }
225
226
                // if clipping is not omitted we will add the rear clipping to our collection.
227
                // We do it here to make sure we get the correct day
228 4
                if (count($entries) === 1 && !$dontClip) {
229
                    // test if the last booking is from the today, if not we have to clip at the end of the last booked day
230 4
                    $bookingTime = new \DateTime($booking->getTime());
231 4
                    $now = new \DateTime();
232 4
                    $interval = $bookingTime->diff($now);
233 4
                    if ($interval->days === 0) {
234
                        $entries[] = BookingFactory::getBooking('', Clipping::CLIPPING_TAG_REAR);
235
                    } else {
236 4
                        $entries[] = BookingFactory::getBooking('', Clipping::CLIPPING_TAG_REAR, date('Y-m-d', strtotime($booking->getTime()) + 24 * 60 * 60));
237
                    }
238
                    // reverse entries array to let it start with our clipping again
239 4
                    $entries = array_reverse($entries);
240
                }
241
242
                // collect keys we found something for, for later re-use
243 4
                $bookingKey = $key;
244
245
                // break if we got as much bookings as our limit is
246 4
                if (!is_null($limit) && $limit <= $bookingCount) {
247 4
                    break;
248
                }
249
            }
250
        }
251
252
        // entries still empty? Then we can quit here
253 4
        if (empty($entries)) {
254
            return $entries;
255
        }
256
257
        // clip the front, but only if we filter by from date
258 4
        if (!$dontClip && $fromDate !== 0) {
259 2
            $entries[] = BookingFactory::getBooking('', Clipping::CLIPPING_TAG_FRONT, $fromDate);
260
261
            // move some bookings into the past to get the startbooking of a potential task we might need
262 2
            for ($i = $bookingKey + 1; $i < count($rawEntries); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
263 2
                if (empty(trim($rawEntries[$i]))) {
264
                    continue;
265
                }
266 2
                $entry = explode(self::SEPARATOR, trim($rawEntries[$i], ' |'));
267 2
                $comment = isset($entry[2]) ? $entry[2] : '';
268 2
                $pushed = isset($entry[3]) && !empty($entry[3]) ? true : false;
269 2
                $booking = BookingFactory::getBooking($comment, $entry[1], $entry[0], $pushed);
270 2
                $entries[] = $booking;
271
                // break after the first non-meta booking
272 2
                if (!$booking->isMetaBooking()) {
273 2
                    break;
274
                }
275
            }
276
        }
277
278 4
        return $entries;
279
    }
280
}
281