ProductRepository::store()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 16
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 1
Metric Value
c 3
b 0
f 1
dl 0
loc 16
rs 9.4285
cc 2
eloc 9
nc 2
nop 1
1
<?php namespace App\Repositories;
2
3
use App\Exceptions\RepositoryException;
4
use App\Models\Products;
5
use Carbon\Carbon;
6
use Carbon\CarbonInterval;
7
use DB;
8
use Illuminate\Database\Eloquent\Collection;
9
use Session;
10
use stdClass;
11
use Validator;
12
13
class ProductRepository extends Repository {
14
15
    public function getModelName()
16
    {
17
        return 'App\Models\Products';
18
    }
19
20
	public function all() {
21
22
		try {
23
			return $this->model->group( Session::get('groupID') )->get();
24
		}
25
		catch(\Exception $e) {
26
			throw new RepositoryException('Database error', RepositoryException::DATABASE_ERROR);
27
		}
28
	}
29
30
	public function get($id) {
31
		
32
		$this->validateID($id);
33
34
		try {
35
			return $this->model->group( Session::get('groupID') )->where('product_id', $id)->first();
36
		}
37
		catch(\Exception $e) {
38
			throw new RepositoryException('Database error', RepositoryException::DATABASE_ERROR);
39
		}
40
	}
41
42
	public function store(array $data) {
43
44
		$this->validate($data);
45
46
		$product = $this->createModel($data);
47
48
		try {
49
			$product->save();
50
		}
51
		catch(\Exception $e) {
52
			throw new RepositoryException('Database error', RepositoryException::DATABASE_ERROR);
53
		}
54
55
		$product->id = DB::getPdo()->lastInsertId();
56
		return $product;
57
	}
58
59
	public function update($id, array $data) {
60
61
		$this->validateID($id);
62
		$this->validate($data, false);
63
64
		try {
65
			$product = $this->model->group( Session::get('groupID') )->withTrashed()->find($id);
66
		}
67
		catch(\Exception $e) {
68
			throw new RepositoryException('Database error while fetching'.$e->getMessage(), RepositoryException::DATABASE_ERROR);
69
		}
70
71
		if( $product == null )
72
			throw new RepositoryException('Product with ID '.$id.' not found', RepositoryException::RESOURCE_NOT_FOUND);
73
74
		if( $product->trashed() )
75
			throw new RepositoryException('Product with ID '.$id.' has been deleted', RepositoryException::RESOURCE_DENIED);
76
77
		$this->createModel($data, $product);
78
79
		try {
80
			$product->save();
81
		}
82
		catch(\Exception $e) {
83
			throw new RepositoryException('Database error while saving', RepositoryException::DATABASE_ERROR);
84
		}
85
86
		return $product;
87
	}
88
89
    public function decrementQuantity($id, $number) {
90
91
        $this->validateID($id);
92
93
        // Not the function intended to validate numbers,
94
        // but does exact the same thing: validate a positive integer
95
        $this->validateID($number);
96
        $number = intval($number);
97
98
        try {
99
            $product = $this->model->findOrFail($id);
100
101
            if( ($product->quantity-$number) >= 0 )
102
            {
103
                $product->quantity -= $number;
104
            }
105
            else
106
            {
107
                $product->quantity = 0;
108
            }
109
110
            $product->save();
111
        }
112
        catch(\Exception $e) {
113
            throw new RepositoryException('Could not decrement product number:'.$e->getMessage(), RepositoryException::DATABASE_ERROR);
114
        }
115
116
        return $product->quantity;
117
    }
118
119
	public function softDelete($id) {
120
121
		$this->validateID($id);
122
123
		try {
124
			$product = $this->model->group( Session::get('groupID') )->withTrashed()->find($id);
125
		}
126
		catch(\Exception $e) {
127
			throw new RepositoryException('Database error while fetching', RepositoryException::DATABASE_ERROR);
128
		}
129
130
		if( $product == null )
131
			throw new RepositoryException('Product with ID'.$id.' not found', RepositoryException::RESOURCE_NOT_FOUND);
132
133
		if( $product->trashed() )
134
			throw new RepositoryException('Product with ID '.$id.' has been deleted', RepositoryException::RESOURCE_DENIED);
135
136
		try {
137
			$product->delete();
138
		}
139
		catch(\Exception $e) {
140
			throw new RepositoryException('Database error while deleting', RepositoryException::DATABASE_ERROR);
141
		}
142
143
		return $product;
144
	}
145
146
    /**
147
     * Returns a top-10 from the most sold product in a given interval.
148
     *
149
     * Watch out, deleted products are also taken in the results!
150
     *
151
     * @param CarbonInterval $interval
152
     * @return mixed
153
     * @throws RepositoryException
154
     */
155
    public function rankBySalesInInterval(CarbonInterval $interval)
156
    {
157
        $beginDate = Carbon::now()->sub($interval)->addHour();
158
159
        if( $interval->d>0 )
160
        {
161
            $beginDate = $beginDate->startOfDay();
162
        }
163
164
        try
165
        {
166
            $productRank = $this->model->select(['products.*', DB::raw('SUM(sale_details.quantity) as sale_count')])
167
                ->leftJoin('sale_details', 'products.product_id', '=', 'sale_details.product_id')
168
                ->join('sales', 'sales.sale_id', '=', 'sale_details.sale_id')
169
                ->where('sales.is_active', '=', true)
170
                ->where('sales.time', '>=', $beginDate)
171
                ->groupBy('sale_details.product_id')
172
                ->orderBy('sale_count', 'DESC')
173
                ->orderBy('products.product_name', 'ASC')
174
                ->take(10)
175
                ->withTrashed()
176
                ->get();
177
        }
178
        catch(\Exception $e)
179
        {
180
            throw new RepositoryException('Could not retrieve product ranking', RepositoryException::DATABASE_ERROR);
181
        }
182
183
        return $productRank;
184
    }
185
186
	/**
187
	 * Format a Product object or an Eloquent Collection to a REST format
188
	 *
189
	 * @param  	object 	$products 	MUST be a Product object or an Eloquent Collection
190
	 * @return 	array
191
	 */
192
	public function APIFormat($products)
193
    {
194
        if($products instanceof Products) {
195
            return [$this->formatRecord($products)];
196
        }
197
198
		$responseArray = [];
199
		foreach ($products as $product) {
200
			array_push($responseArray, $this->formatRecord( $product ));
201
		}
202
203
		return $responseArray;
204
	}
205
206
	/**
207
	 * Validates an array of data
208
	 *
209
	 * @param 	array 	$data 		 	Data array of the form: column_alias => value_to_validate
210
	 * @param 	bool 	$required 	 	Indicates if validation must follow 'required' instructions
211
	 * @return 	void
212
	 * @throws 	RepositoryException 	If the validation failed
213
	 */
214
	public function validate(array $data, $required=true)
215
    {
216
		$rules = Products::$validationRules;
217
218
		if( $required === false ) {
219
220
			foreach ($rules as $rule => $value) {
221
222
				$rules[$rule] = str_replace('required', '', $value);
223
			}
224
		}
225
226
		$validator = Validator::make($data, $rules);
227
228
		if( $validator->fails() ) {
229
			throw new RepositoryException('Validation failed', RepositoryException::VALIDATION_FAILED);
230
		}
231
	}
232
233
	/**
234
	 * Create or update an Eloquent model with the specified data
235
	 *
236
	 * @param  	array 	$data  	Data array with the new data
237
	 * @param  	object  $model  Existing Eloquent model to update. If NULL, a new model will be created
238
	 * @return  null|object 	The new or updated Eloquent model
239
	 */
240
	private function createModel($data, $model=NULL)
241
    {
242
		if( $model == NULL )
243
			$model = new Products();
244
245
		$columnAlias = ['category'     => 'category_id',
246
						'name'         => 'product_name',
247
						'price'        => 'price',
248
						'quantity'     => 'quantity',
249
						'description'  => 'description' ];
250
251
		foreach ($data as $name => $value) {
252
			
253
			if( !isset( $columnAlias[$name] ) )
254
				continue;
255
256
			if( $value !== '' )
257
				$model->$columnAlias[$name] = $value;
258
		}
259
260
		return $model;
261
	}
262
263
	/**
264
	 * Format an Eloquent 'record' into a REST oriented object
265
	 *
266
	 * @param  	object  $product  	An Eloquent object that represents a record 
267
	 * @return  object 				A stdObject which contains some casted attributes
268
	 */
269
	private function formatRecord($product)
270
    {
271
		$productObject = new stdClass();
272
			
273
		$productObject->id       = intval($product->product_id);
274
		$productObject->category = intval($product->category_id);
275
		$productObject->price    = floatval($product->price);
276
		$productObject->quantity = intval($product->quantity);
277
278
		$productObject->name 		= $product->product_name;
279
		$productObject->description = $product->description;
280
281
		return $productObject;
282
	}
283
}