Completed
Push — master ( af2910...cc2184 )
by Bram
02:11
created

Reservation::TicketFile()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
/**
3
 * Reservation.php
4
 *
5
 * @author Bram de Leeuw
6
 * Date: 09/03/17
7
 */
8
9
namespace Broarm\EventTickets;
10
11
use CalendarEvent;
12
use CalendarEvent_Controller;
13
use DataObject;
14
use Director;
15
use Dompdf\Dompdf;
16
use FieldList;
17
use File;
18
use Folder;
19
use GridField;
20
use GridFieldConfig_RecordViewer;
21
use HasManyList;
22
use ManyManyList;
23
use Member;
24
use ReadonlyField;
25
use SiteConfig;
26
use SSViewer;
27
use Tab;
28
use TabSet;
29
use ViewableData;
30
31
/**
32
 * Class Reservation
33
 *
34
 * @package Broarm\EventTickets
35
 *
36
 * @property string Status
37
 * @property string Title
38
 * @property float  Subtotal
39
 * @property float  Total
40
 * @property string Email todo determine obsolete value
41
 * @property string Comments
42
 * @property string ReservationCode
43
 * @property string Gateway
44
 *
45
 * @property int    EventID
46
 * @property int    MainContactID
47
 *
48
 * @method CalendarEvent|TicketExtension Event()
49
 * @method Attendee MainContact()
50
 * @method HasManyList Payments()
51
 * @method HasManyList Attendees()
52
 * @method ManyManyList PriceModifiers()
53
 */
54
class Reservation extends DataObject
55
{
56
    /**
57
     * Time to wait before deleting the discarded cart
58
     * Give a string that is parsable by strtotime
59
     *
60
     * @var string
61
     */
62
    private static $delete_after = '+1 week';
1 ignored issue
show
Unused Code introduced by
The property $delete_after 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...
63
64
    private static $db = array(
2 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
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...
65
        'Status' => 'Enum("CART,PENDING,PAID,CANCELED","CART")',
66
        'Title' => 'Varchar(255)',
67
        'Subtotal' => 'Currency',
68
        'Total' => 'Currency',
69
        'Email' => 'Varchar(255)',
70
        'Gateway' => 'Varchar(255)',
71
        'Comments' => 'Text',
72
        'ReservationCode' => 'Varchar(255)'
73
    );
74
75
    private static $has_one = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
Unused Code introduced by
The property $has_one 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...
76
        'Event' => 'CalendarEvent',
77
        //'TicketFile' => 'File',
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
78
        'MainContact' => 'Broarm\EventTickets\Attendee'
79
    );
80
81
    private static $has_many = array(
1 ignored issue
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
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...
82
        'Payments' => 'Payment',
83
        'Attendees' => 'Broarm\EventTickets\Attendee.Reservation'
84
    );
85
86
    private static $belongs_many_many = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
Unused Code introduced by
The property $belongs_many_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...
87
        'PriceModifiers' => 'Broarm\EventTickets\PriceModifier'
88
    );
89
90
    private static $indexes = array(
2 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
Unused Code introduced by
The property $indexes 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...
91
        'ReservationCode' => 'unique("ReservationCode")'
92
    );
93
94
    private static $summary_fields = array(
1 ignored issue
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
Unused Code introduced by
The property $summary_fields 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...
95
        'Title' => 'Customer',
96
        'Total.Nice' => 'Total',
97
        'State' => 'Status'
98
    );
99
100
    public function getCMSFields()
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
101
    {
102
        $fields = new FieldList(new TabSet('Root', $mainTab = new Tab('Main')));
103
        $gridFieldConfig = GridFieldConfig_RecordViewer::create();
104
        $fields->addFieldsToTab('Root.Main', array(
105
            ReadonlyField::create('ReservationCode', _t('Reservation.Code', 'Code')),
106
            ReadonlyField::create('Title', _t('Reservation.MainContact', 'Main contact')),
107
            ReadonlyField::create('Gateway', _t('Reservation.Gateway', 'Gateway')),
108
            ReadonlyField::create('Total', _t('Reservation.Total', 'Total')),
109
            ReadonlyField::create('Comments', _t('Reservation.Comments', 'Comments')),
110
            GridField::create('Attendees', 'Attendees', $this->Attendees(), $gridFieldConfig),
111
            GridField::create('Payments', 'Payments', $this->Payments(), $gridFieldConfig)
112
        ));
113
        $fields->addFieldsToTab('Root.Main', array());
114
        $this->extend('updateCMSFields', $fields);
115
        return $fields;
116
    }
117
118
    public function onBeforeWrite()
119
    {
120
        // Set the title to the name of the reservation holder
121
        $this->Title = $this->getName();
122
123
        // Create a validation code to be used for confirmation and in the barcode
124
        if ($this->exists() && empty($this->ReservationCode)) {
125
            $this->ReservationCode = $this->createReservationCode();
126
        }
127
128
        parent::onBeforeWrite();
129
    }
130
131
    public function onBeforeDelete()
132
    {
133
        // If a reservation is deleted remove the names from the guest list
134
        foreach ($this->Attendees() as $attendee) {
135
            /** @var Attendee $attendee */
136
            if ($attendee->exists()) {
137
                $attendee->delete();
138
            }
139
        }
140
141
        // Make sure the ticket file is not downloadable
142
        //if ($this->TicketFile()->exists()) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
74% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
143
        //    $this->TicketFile()->delete();
0 ignored issues
show
Unused Code Comprehensibility introduced by
73% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
144
        //}
145
146
        // Remove the folder
147
        if ($this->fileFolder()->exists()) {
148
            $this->fileFolder()->delete();
149
        }
150
151
        parent::onBeforeDelete();
152
    }
153
154
    public function singular_name()
155
    {
156
        $name = explode('\\', parent::singular_name());
157
        return trim(end($name));
158
    }
159
160
    /**
161
     * Check if the cart is still in cart state and the delete_after time period has been exceeded
162
     *
163
     * @return bool
164
     */
165
    public function isDiscarded()
166
    {
167
        $deleteAfter = strtotime(self::config()->get('delete_after'), strtotime($this->Created));
168
        return ($this->Status === 'CART') && (time() > $deleteAfter);
169
    }
170
171
    /**
172
     * Get the full name
173
     *
174
     * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be string|null?

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...
175
     */
176
    public function getName()
177
    {
178
        /** @var Attendee $attendee */
179
        if ($this->MainContact()->exists()) {
180
            return $this->MainContact()->getName();
181
        } else {
182
            return 'new reservation';
183
        }
184
    }
185
186
    /**
187
     * Return the translated state
188
     * @return string
189
     */
190
    public function getState()
191
    {
192
        return _t("Reservation.{$this->Status}", $this->Status);
193
    }
194
195
    /**
196
     * Get the total by querying the sum of attendee ticket prices
197
     *
198
     * @return float
199
     */
200
    public function calculateTotal()
201
    {
202
        $total = $this->Subtotal = $this->Attendees()->leftJoin(
203
            'Broarm\EventTickets\Ticket',
204
            '`Broarm\EventTickets\Attendee`.`TicketID` = `Broarm\EventTickets\Ticket`.`ID`'
205
        )->sum('Price');
206
207
        // Calculate any price modifications if added
208
        if ($this->PriceModifiers()->exists()) {
209
            foreach ($this->PriceModifiers() as $priceModifier) {
210
                $priceModifier->updateTotal($total);
211
            }
212
        }
213
214
        return $this->Total = $total;
215
    }
216
217
    /**
218
     * Safely change to a state
219
     *
220
     * @param $state
221
     */
222
    public function changeState($state)
223
    {
224
        $availableStates = $this->dbObject('Status')->enumValues();
225
        if (in_array($state, $availableStates)) {
226
            $this->Status = $state;
227
        } else {
228
            user_error(_t('Reservation.STATE_CHANGE_ERROR', 'Selected state is not available'));
229
        }
230
    }
231
232
    /**
233
     * Set the main contact id
234
     *
235
     * @param $id
236
     */
237
    public function setMainContact($id) {
238
        $this->MainContactID = $id;
239
        $this->write();
240
    }
241
242
    /**
243
     * Create a reservation code
244
     *
245
     * @return string
246
     */
247
    public function createReservationCode()
248
    {
249
        return uniqid($this->ID);
250
    }
251
252
    /**
253
     * Create the folder for the qr code and ticket file
254
     *
255
     * @return Folder|DataObject|null
256
     */
257
    public function fileFolder()
258
    {
259
        return Folder::find_or_make("/event-tickets/{$this->ReservationCode}/");
260
    }
261
262
    /**
263
     * Generate the qr codes and downloadable pdf
264
     */
265
    public function createFiles()
266
    {
267
        $folder = $this->fileFolder();
268
        /** @var Attendee $attendee */
269
        foreach ($this->Attendees() as $attendee) {
270
            $attendee->createQRCode($folder);
271
            $attendee->createTicketFile($folder);
272
        }
273
    }
274
275
    public function canView($member = null)
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
276
    {
277
        return $this->Event()->canView($member);
278
    }
279
280
    public function canEdit($member = null)
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
281
    {
282
        return $this->Event()->canEdit($member);
1 ignored issue
show
Bug introduced by
The method canEdit does only exist in Broarm\EventTickets\TicketExtension, but not in CalendarEvent.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
283
    }
284
285
    public function canDelete($member = null)
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
286
    {
287
        return $this->Event()->canDelete($member);
1 ignored issue
show
Bug introduced by
The method canDelete does only exist in Broarm\EventTickets\TicketExtension, but not in CalendarEvent.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
288
    }
289
290
    public function canCreate($member = null)
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
291
    {
292
        return $this->Event()->canCreate($member);
1 ignored issue
show
Bug introduced by
The method canCreate does only exist in Broarm\EventTickets\TicketExtension, but not in CalendarEvent.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
293
    }
294
}
295