Completed
Branch dev (81ae86)
by
unknown
27:37 queued 17:44
created

DefaultPrices::cloneDefaultPrices()   B

Complexity

Conditions 10
Paths 13

Size

Total Lines 41

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 10
nc 13
nop 5
dl 0
loc 41
rs 7.6666
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace EventEspresso\core\domain\services\admin\entities;
4
5
use EE_Base_Class;
6
use EE_Error;
7
use EE_Price;
8
use EE_Price_Type;
9
use EE_Ticket;
10
use EEM_Price;
11
use EEM_Price_Type;
12
use EventEspresso\core\exceptions\InvalidEntityException;
13
use EventEspresso\core\exceptions\InvalidInterfaceException;
14
use ReflectionException;
15
use RuntimeException;
16
17
/**
18
 * Class DefaultPrices
19
 * Description
20
 *
21
 * @package EventEspresso\core\domain\services\admin\events\editor
22
 * @author  Brent Christensen
23
 * @since   $VID:$
24
 */
25
class DefaultPrices implements DefaultEntityGeneratorInterface
26
{
27
28
    /**
29
     * @var EEM_Price
30
     */
31
    protected $price_model;
32
33
    /**
34
     * @var EEM_Price_Type
35
     */
36
    protected $price_type_model;
37
38
    /**
39
     * @var EE_Price[]
40
     */
41
    protected $new_prices = [];
42
43
    /**
44
     * @var EE_Price[]
45
     */
46
    protected $taxes = [];
47
48
49
    /**
50
     * @param EEM_Price      $price_model
51
     * @param EEM_Price_Type $price_type_model
52
     */
53
    public function __construct(EEM_Price $price_model, EEM_Price_Type $price_type_model)
54
    {
55
        $this->price_model      = $price_model;
56
        $this->price_type_model = $price_type_model;
57
    }
58
59
60
    /**
61
     * @param EE_Ticket|EE_Base_Class $entity
62
     * @return EE_Price[]
63
     * @throws EE_Error
64
     * @throws InvalidInterfaceException
65
     * @throws ReflectionException
66
     * @since $VID:$
67
     */
68
    public function create(EE_Base_Class $entity): array
69
    {
70
        if (! $entity instanceof EE_Ticket) {
71
            throw new InvalidEntityException($entity, 'EE_Ticket');
72
        }
73
        $is_free                   = true;
74
        $has_base_price            = false;
75
        $remove_existing_relations = true;
76
        // first, let's get all of the default taxes for the site
77
        $this->taxes = $this->price_model->getAllDefaultTaxes();
78
        // then separate taxes from the other prices for the existing default ticket prices
79
        $default_prices = $this->separateTaxesFromOtherPrices($entity->prices());
80
        // but if that's empty, then let's get the default global prices
81
        if (empty($default_prices)) {
82
            $default_global_prices     = $this->price_model->get_all_default_prices();
83
            $default_prices            = $this->separateTaxesFromOtherPrices($default_global_prices);
84
            $remove_existing_relations = false;
85
        }
86
        // then clone and apply all of the default prices
87
        [$has_base_price, $is_free] = $this->cloneDefaultPrices(
88
            $entity,
89
            $default_prices,
90
            $remove_existing_relations,
91
            $has_base_price,
92
            $is_free
93
        );
94
        if (! $has_base_price) {
95
            $new_base_price                            = $this->createNewBasePrice($entity);
96
            $this->new_prices[ $new_base_price->ID() ] = $new_base_price;
97
        }
98
        $this->applyTaxes($entity, $is_free);
99
        $ticket_total = $entity->get_ticket_total_with_taxes(true);
100
        if ($ticket_total !== $entity->ticket_price()) {
101
            $entity->set_price($ticket_total);
102
            $entity->save();
103
        }
104
        return $this->new_prices;
105
    }
106
107
108
    /**
109
     * @param EE_Ticket $ticket
110
     * @param bool      $is_free
111
     * @throws EE_Error
112
     * @throws ReflectionException
113
     */
114
    private function applyTaxes(EE_Ticket $ticket, bool $is_free)
115
    {
116
        if (! $is_free && ! empty($this->taxes)) {
117
            foreach ($this->taxes as $tax) {
118
                // assign taxes but don't duplicate them because they operate globally
119
                $ticket->set_taxable(true);
120
                $tax->_add_relation_to($ticket, 'Ticket');
121
            }
122
        }
123
    }
124
125
126
    /**
127
     * @param EE_Ticket  $ticket
128
     * @param EE_Price[] $default_prices
129
     * @param bool       $remove_existing_relations
130
     * @param bool       $has_base_price
131
     * @param bool       $is_free
132
     * @return bool[]
133
     * @throws EE_Error
134
     * @throws ReflectionException
135
     */
136
    private function cloneDefaultPrices(
137
        EE_Ticket $ticket,
138
        array $default_prices,
139
        bool $remove_existing_relations,
140
        bool $has_base_price,
141
        bool $is_free
142
    ): array {
143
        foreach ($default_prices as $default_price) {
144
            // duplicate the default price so that it does not get mutated
145
            $default_price_clone = clone $default_price;
146
            if ($remove_existing_relations) {
147
                $ticket->_remove_relation_to($default_price, 'Price');
148
            }
149
            if ((
150
                    // has non-zero base price
151
                    $default_price_clone->is_base_price()
152
                    && $default_price_clone->amount() > 0
153
                )
154
                || (
155
                    // or has fixed amount surcharge
156
                    $default_price_clone->is_surcharge()
157
                    && ! $default_price_clone->is_percent()
158
                )
159
            ) {
160
                $is_free = false;
161
            }
162
            $is_base_price = $default_price_clone->is_base_price();
163
            // add this price to ticket if it is a regular price modifier, ie: NOT a base price,
164
            // OR if it IS a base price but this ticket does NOT already have a base price
165
            if (! $is_base_price || ! $has_base_price) {
166
                $default_price_clone->set('PRC_ID', null);
167
                $default_price_clone->set('PRC_is_default', false);
168
                $default_price_clone->save();
169
                $default_price_clone->_add_relation_to($ticket, 'Ticket');
170
                $this->new_prices[ $default_price_clone->ID() ] = $default_price_clone;
171
                // then recheck that a base price has been set so that we don't add another one
172
                $has_base_price = $is_base_price ? true : $has_base_price;
173
            }
174
        }
175
        return [$has_base_price, $is_free];
176
    }
177
178
179
    /**
180
     * @param EE_Ticket $ticket
181
     * @return EE_Price
182
     * @throws EE_Error
183
     * @throws ReflectionException
184
     */
185
    private function createNewBasePrice(EE_Ticket $ticket): EE_Price
186
    {
187
        $new_base_price  = $this->price_model->get_new_price();
188
        $base_price_type = $this->price_type_model->get_one(
189
            [
190
                [
191
                    'PBT_ID' => EEM_Price_Type::base_type_base_price,
192
                ],
193
            ]
194
        );
195
        if (! $base_price_type instanceof EE_Price_Type) {
196
            throw new RuntimeException(
197
                esc_html__(
198
                    'A valid base price type could not be retrieved from the database.',
199
                    'event_espresso'
200
                )
201
            );
202
        }
203
        $new_base_price->set('PRT_ID', $base_price_type->ID());
204
        $new_base_price->set('PRC_is_default', false);
205
        $new_base_price->save();
206
        $new_base_price->_add_relation_to($ticket, 'Ticket');
207
        return $new_base_price;
208
    }
209
210
211
    /**
212
     * @param array $prices
213
     * @return array
214
     * @throws EE_Error
215
     * @throws ReflectionException
216
     */
217
    private function separateTaxesFromOtherPrices(array $prices = []): array
218
    {
219
        $default_prices = [];
220
        if (is_array($prices)) {
221
            foreach ($prices as $key => $price) {
222
                if (! $price instanceof EE_Price) {
223
                    throw new InvalidEntityException($price, 'EE_Price');
224
                }
225
                // grab any taxes but don't do anything just yet
226
                if ($price->is_tax()) {
227
                    $this->taxes[ $price->ID() ] = $price;
228
                    continue;
229
                }
230
                $default_prices[ $price->ID() ] = $price;
231
            }
232
        }
233
        return $default_prices;
234
    }
235
}
236