Completed
Push — master ( 81d10e...3eebf6 )
by Bernhard
01:55
created

File::storeNewestStorageContent()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 5
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
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    Bernhard Wick <[email protected]>
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    Bernhard Wick <[email protected]>
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
    public function __construct()
77
    {
78
        // calculate the default file path
79
        $this->logFilePath = dirname(dirname(__DIR__)) . DIRECTORY_SEPARATOR . 'data' . DIRECTORY_SEPARATOR . self::DATA_NAME;
80
        // check if the file exists, if not create it
81
        if (!is_file($this->logFilePath)) {
82
            touch($this->logFilePath);
83
        }
84
    }
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
     */
141
    protected function storeNewestStorageContent($bookString)
142
    {
143
        $path = $this->getLogFilePath();
144
        file_put_contents($path, $bookString . $this->getStorageContent());
145
    }
146
147
    /**
148
     * Get the content of the files storage
149
     *
150
     * @return string
151
     */
152
    protected function getStorageContent()
153
    {
154
        return file_get_contents($this->getLogFilePath());
155
    }
156
157
    /**
158
     * Retrieves retrieves the last booking from the storage
159
     *
160
     * @param boolean $includeMetaTickets Whether or not the retrieved booking can be a meta ticket
161
     *
162
     * @return \Wicked\Timely\Entities\Booking
163
     */
164
    public function retrieveLast($includeMetaTickets = false) {
165
        $tmp = $this->retrieve(null, null, null, 1, true, $includeMetaTickets);
166
        return array_pop($tmp);
167
    }
168
169
    /**
170
     * Retrieves one or several bookings from the storage. Bookings can be filtered by pattern,
171
     * date, etc.
172
     *
173
     * @param null|string  $pattern   A pattern to filter ticket IDs for. Defaults to NULL
174
     * @param null|integer $toDate    Date up to which bookings will be returned. Defaults to NULL
175
     * @param null|integer $fromDate  Date from which on bookings will be returned. Defaults to NULL
176
     * @param null|integer $limit     Number of non-meta bookings the retrieval is limited to. Defaults to NULL
177
     * @param boolean      $dontClip  Whether or not the retrieved bookings should be clipped where appropriate. Defaults to FALSE
178
     * @param boolean      $countMeta Whether or not meta tickets will be included in the counter which is used for our limit
179
     *
180
     * @return \Wicked\Timely\Entities\Booking[]
181
     */
182
    public function retrieve($pattern = null, $toDate = null, $fromDate = null, $limit = null, $dontClip = false, $countMeta = false)
183
    {
184
        // test if we got a pattern, if not match against all
185
        if (is_null($pattern)) {
186
            $pattern = '*';
187
        }
188
        // test if we got some dates to filter by
189
        if (is_null($toDate)) {
190
            $toDate = 9999999999;
191
        }
192
        if (is_null($fromDate)) {
193
            $fromDate = 0;
194
        }
195
196
        // get the raw entries
197
        $this->lastRetrieve = $this->getStorageContent();
198
        $rawEntries = explode(self::LINE_BREAK, rtrim($this->lastRetrieve, self::LINE_BREAK));
199
200
        $entries = array();
201
202
        // iterate them and generate the entities
203
        $bookingKey = null;
204
        $bookingCount = 0;
205
        foreach ($rawEntries as $key => $rawEntry) {
206
            // get the potential entry and filter them by ticket ID
207
            $entry = explode(self::SEPARATOR, trim($rawEntry, ' |'));
208
            $timestamp = strtotime($entry[0]);
209
            if (isset($entry[1]) &&
210
                (fnmatch($pattern, $entry[1]) || isset(BookingFactory::getAllMetaTicketIds()[$entry[1]])) &&
211
                $timestamp > $fromDate && $timestamp < $toDate
212
            ) {
213
                // collect the actual booking
214
                $comment = isset($entry[2]) ? $entry[2] : '';
215
                $pushed = isset($entry[3]) && !empty($entry[3]) ? true : false;
216
                $booking = BookingFactory::getBooking($comment, $entry[1], $entry[0], $pushed);
217
                $entries[] = $booking;
218
219
                // increase the booking counter
220
                if (!$booking->isMetaBooking() || $countMeta) {
221
                    $bookingCount ++;
222
                }
223
224
                // if clipping is not omitted we will add the rear clipping to our collection.
225
                // We do it here to make sure we get the correct day
226
                if (count($entries) === 1 && !$dontClip) {
227
                    // test if the last booking is from the today, if not we have to clip at the end of the last booked day
228
                    $bookingTime = new \DateTime($booking->getTime());
229
                    $now = new \DateTime();
230
                    $interval = $bookingTime->diff($now);
231
                    if ($interval->days === 0) {
232
                        $entries[] = BookingFactory::getBooking('', Clipping::CLIPPING_TAG_REAR);
233
                    } else {
234
                        $entries[] = BookingFactory::getBooking('', Clipping::CLIPPING_TAG_REAR, date('Y-m-d', strtotime($booking->getTime()) + 24 * 60 * 60));
235
                    }
236
                    // reverse entries array to let it start with our clipping again
237
                    $entries = array_reverse($entries);
238
                }
239
240
                // collect keys we found something for, for later re-use
241
                $bookingKey = $key;
242
243
                // break if we got as much bookings as our limit is
244
                if (!is_null($limit) && $limit <= $bookingCount) {
245
                    break;
246
                }
247
            }
248
        }
249
250
        // entries still empty? Then we can quit here
251
        if (empty($entries)) {
252
            return $entries;
253
        }
254
255
        // clip the front, but only if we filter by from date
256
        if (!$dontClip && $fromDate !== 0) {
257
            $entries[] = BookingFactory::getBooking('', Clipping::CLIPPING_TAG_FRONT, $fromDate);
258
259
            // move some bookings into the past to get the startbooking of a potential task we might need
260
            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...
261
                if (empty(trim($rawEntries[$i]))) {
262
                    continue;
263
                }
264
                $entry = explode(self::SEPARATOR, trim($rawEntries[$i], ' |'));
265
                $comment = isset($entry[2]) ? $entry[2] : '';
266
                $pushed = isset($entry[3]) && !empty($entry[3]) ? true : false;
267
                $booking = BookingFactory::getBooking($comment, $entry[1], $entry[0], $pushed);
268
                $entries[] = $booking;
269
                // break after the first non-meta booking
270
                if (!$booking->isMetaBooking()) {
271
                    break;
272
                }
273
            }
274
        }
275
276
        return $entries;
277
    }
278
}
279