Completed
Push — master ( 8c9351...52e005 )
by Bram
04:57
created

TicketExtension::getCheckedInCount()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 4
nc 1
nop 0
1
<?php
2
/**
3
 * TicketExtension.php
4
 *
5
 * @author Bram de Leeuw
6
 * Date: 09/03/17
7
 */
8
9
namespace Broarm\EventTickets;
10
11
use CalendarEvent_Controller;
12
use DataExtension;
13
use FieldList;
14
use GridField;
15
use GridFieldConfig_RecordEditor;
16
use HasManyList;
17
use HtmlEditorField;
18
use LiteralField;
19
use NumericField;
20
use SiteConfig;
21
22
/**
23
 * Class TicketExtension
24
 *
25
 * @package Broarm\EventTickets
26
 *
27
 * @property TicketExtension|\CalendarEvent $owner
28
 * @property int                            Capacity
29
 * @property int                            OrderMin
30
 * @property int                            OrderMax
31
 * @property string                         SuccessMessage
32
 * @property string                         SuccessMessageMail
33
 *
34
 * @method \HasManyList Tickets()
35
 * @method \HasManyList Reservations()
36
 * @method \HasManyList Attendees()
37
 * @method \HasManyList WaitingList()
38
 * @method \HasManyList Fields()
39
 */
40
class TicketExtension extends DataExtension
41
{
42
    /**
43
     * @var CalendarEvent_Controller
44
     */
45
    protected $controller;
46
47
    private static $db = array(
0 ignored issues
show
Unused Code introduced by
The property $db is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
48
        'Capacity' => 'Int',
49
        'OrderMin' => 'Int',
50
        'OrderMax' => 'Int',
51
        'SuccessMessage' => 'HTMLText',
52
        'SuccessMessageMail' => 'HTMLText'
53
    );
54
55
    private static $has_many = array(
0 ignored issues
show
Unused Code introduced by
The property $has_many is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
56
        'Tickets' => 'Broarm\EventTickets\Ticket.Event',
57
        'Reservations' => 'Broarm\EventTickets\Reservation.Event',
58
        'Attendees' => 'Broarm\EventTickets\Attendee.Event',
59
        'WaitingList' => 'Broarm\EventTickets\WaitingListRegistration.Event',
60
        'Fields' => 'Broarm\EventTickets\UserField.Event'
61
    );
62
63
    private static $defaults = array(
0 ignored issues
show
Unused Code introduced by
The property $defaults is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
64
        'Capacity' => 50
65
    );
66
67
    private static $translate = array(
0 ignored issues
show
Unused Code introduced by
The property $translate is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
68
        'SuccessMessage',
69
        'SuccessMessageMail'
70
    );
71
72
    protected $cachedGuestList;
73
74
    public function updateCMSFields(FieldList $fields)
75
    {
76
        $ticketLabel = _t('TicketExtension.Tickets', 'Tickets');
77
        $fields->addFieldsToTab(
78
            "Root.$ticketLabel", array(
79
            GridField::create('Tickets', $ticketLabel, $this->owner->Tickets(), TicketsGridFieldConfig::create($this->canCreateTickets())),
80
            NumericField::create('Capacity', _t('TicketExtension.Capacity', 'Capacity')),
81
            HtmlEditorField::create('SuccessMessage', _t('TicketExtension.SuccessMessage', 'Success message'))->setRows(4),
82
            HtmlEditorField::create('SuccessMessageMail', _t('TicketExtension.MailMessage', 'Mail message'))->setRows(4)
83
        ));
84
85
        // Create Reservations tab
86 View Code Duplication
        if ($this->owner->Reservations()->exists()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
87
            $reservationLabel = _t('TicketExtension.Reservations', 'Reservations');
88
            $fields->addFieldToTab(
89
                "Root.$reservationLabel",
90
                GridField::create('Reservations', $reservationLabel, $this->owner->Reservations(), ReservationGridFieldConfig::create())
91
            );
92
        }
93
94
        // Create Attendees tab
95 View Code Duplication
        if ($this->owner->Attendees()->exists()) {
96
            $guestListLabel = _t('TicketExtension.GuestList', 'GuestList');
97
            $fields->addFieldToTab(
98
                "Root.$guestListLabel",
99
                GridField::create('Attendees', $guestListLabel, $this->owner->Attendees(), GuestListGridFieldConfig::create($this->owner))
100
            );
101
        }
102
103
        // Create WaitingList tab
104 View Code Duplication
        if ($this->owner->WaitingList()->exists()) {
105
            $waitingListLabel = _t('TicketExtension.WaitingList', 'WaitingList');
106
            $fields->addFieldToTab(
107
                "Root.$waitingListLabel",
108
                GridField::create('WaitingList', $waitingListLabel, $this->owner->WaitingList(), GridFieldConfig_RecordEditor::create())
109
            );
110
        }
111
112
        // Create Fields tab
113
        $extraFieldsLabel = _t('TicketExtension.ExtraFields', 'Attendee fields');
114
        $fields->addFieldToTab(
115
            "Root.$extraFieldsLabel",
116
            GridField::create('ExtraFields', $extraFieldsLabel, $this->owner->Fields(), UserFieldsGridFieldConfig::create())
117
        );
118
119
        $this->owner->extend('updateTicketExtensionFields', $fields);
120
    }
121
122
    /**
123
     * Trigger actions after write
124
     */
125
    public function onAfterWrite()
126
    {
127
        $this->createDefaultFields();
128
        parent::onAfterWrite();
129
    }
130
131
    /**
132
     * Creates and sets up the default fields
133
     */
134
    public function createDefaultFields()
135
    {
136
        $fields = Attendee::config()->get('default_fields');
137
        if (!$this->owner->Fields()->exists()) {
138
            foreach ($fields as $fieldName => $config) {
139
                $field = UserField::createDefaultField($fieldName, $config);
140
                $this->owner->Fields()->add($field);
141
            }
142
        }
143
    }
144
145
    /**
146
     * Extend the page actions with an start check in action
147
     *
148
     * @param FieldList $actions
149
     */
150
    public function updateCMSActions(FieldList $actions)
151
    {
152
        $checkInButton = new LiteralField('StartCheckIn',
153
            "<a class='action ss-ui-button ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only'
154
                id='Edit_StartCheckIn'
155
                role='button'
156
                href='{$this->owner->Link('checkin')}'
157
                target='_blank'>
158
                Start check in
159
            </a>"
160
        );
161
162
        if ($this->owner->Attendees()->exists()) {
163
            $actions->push($checkInButton);
164
        }
165
    }
166
167
    /**
168
     * Get the leftover capacity
169
     *
170
     * @return int
0 ignored issues
show
Documentation introduced by
Should the return type not be integer|double?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
171
     */
172
    public function getAvailability()
173
    {
174
        return $this->owner->Capacity - $this->owner->getGuestList()->count();
175
    }
176
177
    /**
178
     * Check if the tickets are still available
179
     *
180
     * @return bool
181
     */
182
    public function getTicketsAvailable()
183
    {
184
        return $this->owner->getAvailability() > 0;
185
    }
186
187
    /**
188
     * Check if the tickets are sold out
189
     * @return bool
190
     */
191
    public function getTicketsSoldOut()
192
    {
193
        return $this->owner->getAvailability() <= 0;
194
    }
195
196
    /**
197
     * get The sale start date
198
     *
199
     * @return \SS_DateTime
200
     */
201
    public function getTicketSaleStartDate()
202
    {
203
        $saleStart = null;
204
        if (($tickets = $this->owner->Tickets())) {
205
            /** @var Ticket $ticket */
206
            foreach ($tickets as $ticket) {
207
                if (($date = $ticket->getAvailableFrom()) && strtotime($date) < strtotime($saleStart) || $saleStart === null) {
208
                    $saleStart = $date;
209
                }
210
            }
211
        }
212
213
        return $saleStart;
214
    }
215
216
    /**
217
     * Check if the event is expired, either by unavailable tickets or because the date has passed
218
     *
219
     * @return bool
220
     */
221
    public function getEventExpired()
222
    {
223
        $expired = false;
224
        if (($tickets = $this->owner->Tickets()) && $expired = $tickets->exists()) {
225
            /** @var Ticket $ticket */
226
            foreach ($tickets as $ticket) {
227
                $expired = (!$ticket->validateDate() && $expired);
228
            }
229
        }
230
231
        return $expired;
232
    }
233
234
    /**
235
     * Check if the ticket sale is still pending
236
     *
237
     * @return bool
238
     */
239
    public function getTicketSalePending()
240
    {
241
        return time() < strtotime($this->owner->getTicketSaleStartDate());
242
    }
243
244
    /**
245
     * Get only the attendees who are certain to attend
246
     * Also includes attendees without any reservation, these are manually added
247
     *
248
     * @return \DataList
249
     */
250
    public function getGuestList()
251
    {
252
        $reservationClass = Reservation::singleton()->getClassName();
253
        $attendeeClass = Attendee::singleton()->getClassName();
254
        return $this->owner->Attendees()
255
            ->leftJoin($reservationClass, "`$attendeeClass`.`ReservationID` = `$reservationClass`.`ID`")
256
            ->filterAny(array(
257
                'ReservationID' => 0,
258
                'Status' => Reservation::STATUS_PAID
259
            ));
260
    }
261
262
    /**
263
     * Get the checked in count for display in templates
264
     *
265
     * @return string
266
     */
267
    public function getCheckedInCount()
268
    {
269
        $attendees = $this->getGuestList();
270
        $checkedIn = $attendees->filter('CheckedIn', true)->count();
271
        return "($checkedIn/{$attendees->count()})";
272
    }
273
274
    /**
275
     * Get the success message
276
     *
277
     * @return mixed|string
278
     */
279 View Code Duplication
    public function getSuccessContent()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
280
    {
281
        if (!empty($this->owner->SuccessMessage)) {
282
            return $this->owner->dbObject('SuccessMessage');
283
        } else {
284
            return SiteConfig::current_site_config()->dbObject('SuccessMessage');
285
        }
286
    }
287
288
    /**
289
     * Get the mail message
290
     *
291
     * @return mixed|string
292
     */
293 View Code Duplication
    public function getMailContent()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
294
    {
295
        if (!empty($this->owner->SuccessMessageMail)) {
296
            return $this->owner->dbObject('SuccessMessageMail');
297
        } else {
298
            return SiteConfig::current_site_config()->dbObject('SuccessMessageMail');
299
        }
300
    }
301
302
    /**
303
     * Get the Ticket logo
304
     *
305
     * @return \Image
306
     */
307
    public function getMailLogo()
308
    {
309
        return SiteConfig::current_site_config()->TicketLogo();
310
    }
311
312
    /**
313
     * Check if the current event can have tickets
314
     *
315
     * @return bool
316
     */
317
    public function canCreateTickets()
318
    {
319
        $currentDate = $this->owner->getController()->CurrentDate();
320
        if ($currentDate && $currentDate->exists()) {
321
            return $currentDate->dbObject('StartDate')->InFuture();
322
        }
323
324
        return false;
325
    }
326
327
    /**
328
     * Get the calendar controller
329
     *
330
     * @return CalendarEvent_Controller
331
     */
332
    public function getController()
333
    {
334
        return $this->controller
335
            ? $this->controller
336
            : $this->controller = CalendarEvent_Controller::create($this->owner);
337
    }
338
}
339