Passed
Push — develop ( dfa246...179c36 )
by Francisco
02:27
created

Exchange::findMatchingExchange()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 2
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace App\Judite\Models;
4
5
use Illuminate\Support\Collection;
6
use Illuminate\Database\Eloquent\Model;
7
use App\Judite\Contracts\ExchangeLogger;
8
use App\Exceptions\MultipleEnrollmentExchangesException;
9
use App\Exceptions\ExchangeEnrollmentWithoutShiftException;
10
use App\Exceptions\ExchangeEnrollmentsOnDifferentCoursesException;
11
12
class Exchange extends Model
13
{
14
    /**
15
     * The relations to eager load on every query.
16
     *
17
     * @var array
18
     */
19
    protected $with = ['fromEnrollment', 'toEnrollment'];
20
21
    /**
22
     * The exchanges logger.
23
     *
24
     * @var \App\Judite\Contracts\ExchangeLogger
25
     */
26
    private $logger;
27
28
    /**
29
     * Create a new Exchange model instance.
30
     *
31
     * @param array $attributes
32
     */
33
    public function __construct(array $attributes = [])
34
    {
35
        parent::__construct($attributes);
36
        $this->logger = resolve(ExchangeLogger::class);
37
    }
38
39
    /**
40
     * Set the enrollments of this exchange.
41
     *
42
     * @param \App\Judite\Models\Enrollment $from
43
     * @param \App\Judite\Models\Enrollment $to
44
     *
45
     * @throws \App\Exceptions\MultipleEnrollmentExchangesException
46
     * @throws \App\Exceptions\ExchangeEnrollmentWithoutShiftException
47
     * @throws \App\Exceptions\ExchangeEnrollmentsOnDifferentCoursesException
48
     *
49
     * @return $this
50
     */
51
    public function setExchangeEnrollments(Enrollment $from, Enrollment $to)
52
    {
53
        // Each enrollment can be requested to exchange once. The students
54
        // are allowed to create only a single exchange related to the
55
        // same enrollment, ensuring that each request exists once.
56
        if ($from->exchangesAsSource()->exists()) {
57
            throw new MultipleEnrollmentExchangesException();
58
        }
59
60
        if ($from->course_id !== $to->course_id) {
61
            throw new ExchangeEnrollmentsOnDifferentCoursesException();
62
        }
63
64
        if (is_null($from->shift_id) || is_null($to->shift_id)) {
65
            throw new ExchangeEnrollmentWithoutShiftException();
66
        }
67
68
        $this->fromEnrollment()->associate($from);
69
        $this->toEnrollment()->associate($to);
70
71
        return $this;
72
    }
73
74
    /**
75
     * Check if an inverse exchange exists.
76
     *
77
     * @param \App\Judite\Models\Enrollment $from
78
     * @param \App\Judite\Models\Enrollment $to
79
     *
80
     * @return \App\Judite\Models\Exchange|null
81
     */
82
    public static function findMatchingExchange(Enrollment $from, Enrollment $to)
83
    {
84
        $inverseMatch = [
85
            'from_enrollment_id' => $to->id,
86
            'to_enrollment_id' => $from->id,
87
        ];
88
89
        return self::where($inverseMatch)->first();
90
    }
91
92
    /**
93
     * Scope a query to only filter exchanges which source enrollment is in a set of values.
94
     *
95
     * @param \Illuminate\Database\Eloquent\Builder $query
96
     * @param mixed                                 $values
97
     *
98
     * @return \Illuminate\Database\Eloquent\Builder
99
     */
100
    public function scopeWhereFromEnrollmentIn($query, $values)
101
    {
102
        return $query->whereIn('from_enrollment_id', $values);
103
    }
104
105
    /**
106
     * Scope a query to only filter exchanges which target enrollment is in a set of values.
107
     *
108
     * @param \Illuminate\Database\Eloquent\Builder $query
109
     * @param mixed                                 $values
110
     *
111
     * @return \Illuminate\Database\Eloquent\Builder
112
     */
113
    public function scopeWhereToEnrollmentIn($query, $values)
114
    {
115
        return $query->whereIn('to_enrollment_id', $values);
116
    }
117
118
    /**
119
     * Perform the exchange and update the associated enrollments.
120
     *
121
     * @return $this
122
     */
123
    public function perform()
124
    {
125
        $fromEnrollmentCopy = clone $this->fromEnrollment;
126
        $toEnrollmentCopy = clone $this->toEnrollment;
127
128
        $this->fromEnrollment->exchange($this->toEnrollment);
129
        $exchangedEnrollments = collect([$this->fromEnrollment, $this->toEnrollment]);
130
        $this->deleteExchangesOfEnrollments($exchangedEnrollments);
131
132
        $this->logger->log($fromEnrollmentCopy, $toEnrollmentCopy);
133
134
        return $this;
135
    }
136
137
    /**
138
     * Get the source enrollment of this exchange.
139
     *
140
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
141
     */
142
    public function fromEnrollment()
143
    {
144
        return $this->belongsTo(Enrollment::class, 'from_enrollment_id');
145
    }
146
147
    /**
148
     * Get the target enrollment of this exchange.
149
     *
150
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
151
     */
152
    public function toEnrollment()
153
    {
154
        return $this->belongsTo(Enrollment::class, 'to_enrollment_id');
155
    }
156
157
    /**
158
     * Deletes all exchanges involving the given enrollments.
159
     *
160
     * @param \Illuminate\Support\Collection $enrollments
161
     */
162
    private function deleteExchangesOfEnrollments(Collection $enrollments)
163
    {
164
        $enrollmentIds = $enrollments->pluck('id');
165
166
        self::whereIn('from_enrollment_id', $enrollmentIds)
167
            ->orWhereIn('to_enrollment_id', $enrollmentIds)
168
            ->delete();
169
    }
170
171
    /**
172
     * Get the course of this exchange.
173
     *
174
     * @return \App\Judite\Models\Course
175
     */
176
    public function course()
177
    {
178
        return $this->fromEnrollment->course;
179
    }
180
181
    /**
182
     * Get the source shift of this exchange.
183
     *
184
     * @return \App\Judite\Models\Shift
185
     */
186
    public function fromShift()
187
    {
188
        return $this->fromEnrollment->shift;
189
    }
190
191
    /**
192
     * Get the target shift of this exchange.
193
     *
194
     * @return \App\Judite\Models\Shift
195
     */
196
    public function toShift()
197
    {
198
        return $this->toEnrollment->shift;
199
    }
200
201
    /**
202
     * Get the source student of this exchange.
203
     *
204
     * @return \App\Judite\Models\Student
205
     */
206
    public function fromStudent()
207
    {
208
        return $this->fromEnrollment->student;
209
    }
210
211
    /**
212
     * Get the target student of this exchange.
213
     *
214
     * @return \App\Judite\Models\Student
215
     */
216
    public function toStudent()
217
    {
218
        return $this->toEnrollment->student;
219
    }
220
}
221