Passed
Pull Request — master (#71)
by Adeniyi
05:43
created

ProductController::destroy()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 9
rs 9.9666
c 0
b 0
f 0
1
<?php
2
3
namespace App\Http\Controllers\Admin\Products;
4
5
use App\Shop\Attributes\Repositories\AttributeRepositoryInterface;
6
use App\Shop\AttributeValues\Repositories\AttributeValueRepositoryInterface;
7
use App\Shop\Brands\Repositories\BrandRepositoryInterface;
8
use App\Shop\Categories\Repositories\Interfaces\CategoryRepositoryInterface;
9
use App\Shop\ProductAttributes\ProductAttribute;
10
use App\Shop\Products\Product;
11
use App\Shop\Products\Repositories\Interfaces\ProductRepositoryInterface;
12
use App\Shop\Products\Repositories\ProductRepository;
13
use App\Shop\Products\Requests\CreateProductRequest;
14
use App\Shop\Products\Requests\UpdateProductRequest;
15
use App\Http\Controllers\Controller;
16
use App\Shop\Products\Transformations\ProductTransformable;
17
use App\Shop\Tools\UploadableTrait;
18
use Illuminate\Http\Request;
19
use Illuminate\Http\UploadedFile;
20
use Illuminate\Support\Facades\Validator;
21
22
class ProductController extends Controller
23
{
24
    use ProductTransformable, UploadableTrait;
25
26
    /**
27
     * @var ProductRepositoryInterface
28
     */
29
    private $productRepo;
30
31
    /**
32
     * @var CategoryRepositoryInterface
33
     */
34
    private $categoryRepo;
35
36
    /**
37
     * @var AttributeRepositoryInterface
38
     */
39
    private $attributeRepo;
40
41
    /**
42
     * @var AttributeValueRepositoryInterface
43
     */
44
    private $attributeValueRepository;
45
46
    /**
47
     * @var ProductAttribute
48
     */
49
    private $productAttribute;
50
51
    private $brandRepo;
52
53
    /**
54
     * ProductController constructor.
55
     *
56
     * @param ProductRepositoryInterface $productRepository
57
     * @param CategoryRepositoryInterface $categoryRepository
58
     * @param AttributeRepositoryInterface $attributeRepository
59
     * @param AttributeValueRepositoryInterface $attributeValueRepository
60
     * @param ProductAttribute $productAttribute
61
     * @param BrandRepositoryInterface $brandRepository
62
     */
63
    public function __construct(
64
        ProductRepositoryInterface $productRepository,
65
        CategoryRepositoryInterface $categoryRepository,
66
        AttributeRepositoryInterface $attributeRepository,
67
        AttributeValueRepositoryInterface $attributeValueRepository,
68
        ProductAttribute $productAttribute,
69
        BrandRepositoryInterface $brandRepository
70
    ) {
71
        $this->productRepo = $productRepository;
72
        $this->categoryRepo = $categoryRepository;
73
        $this->attributeRepo = $attributeRepository;
74
        $this->attributeValueRepository = $attributeValueRepository;
75
        $this->productAttribute = $productAttribute;
76
        $this->brandRepo = $brandRepository;
77
    }
78
79
    /**
80
     * Display a listing of the resource.
81
     *
82
     * @return \Illuminate\Http\Response
83
     */
84
    public function index()
85
    {
86
        $list = $this->productRepo->listProducts('id');
87
88
        if (request()->has('q') && request()->input('q') != '') {
89
            $list = $this->productRepo->searchProduct(request()->input('q'));
90
        }
91
92
        $products = $list->map(function (Product $item) {
93
            return $this->transformProduct($item);
94
        })->all();
95
96
        return view('admin.products.list', [
0 ignored issues
show
Bug Best Practice introduced by
The expression return view('admin.produ...esults($products, 10))) returns the type Illuminate\View\View which is incompatible with the documented return type Illuminate\Http\Response.
Loading history...
97
            'products' => $this->productRepo->paginateArrayResults($products, 10)
98
        ]);
99
    }
100
101
    /**
102
     * Show the form for creating a new resource.
103
     *
104
     * @return \Illuminate\Http\Response
105
     */
106
    public function create()
107
    {
108
        $categories = $this->categoryRepo->listCategories('name', 'asc')->where('parent_id', 1);
109
110
        return view('admin.products.create', [
0 ignored issues
show
Bug Best Practice introduced by
The expression return view('admin.produ...andRepo->listBrands())) returns the type Illuminate\View\View which is incompatible with the documented return type Illuminate\Http\Response.
Loading history...
111
            'categories' => $categories,
112
            'brands' => $this->brandRepo->listBrands()
113
        ]);
114
    }
115
116
    /**
117
     * Store a newly created resource in storage.
118
     *
119
     * @param  CreateProductRequest $request
120
     * @return \Illuminate\Http\Response
121
     */
122
    public function store(CreateProductRequest $request)
123
    {
124
        $data = $request->except('_token', '_method');
125
        $data['slug'] = str_slug($request->input('name'));
126
127
        if ($request->hasFile('cover') && $request->file('cover') instanceof UploadedFile) {
128
            $data['cover'] = $this->productRepo->saveCoverImage($request->file('cover'));
129
        }
130
131
        $product = $this->productRepo->createProduct($data);
132
        $this->saveProductImages($request, $product);
133
134
        if ($request->has('categories')) {
135
            $product->categories()->sync($request->input('categories'));
136
        } else {
137
            $product->categories()->detach();
138
        }
139
140
        return redirect()
0 ignored issues
show
Bug Best Practice introduced by
The expression return redirect()->route...', 'Create successful') returns the type Illuminate\Http\RedirectResponse which is incompatible with the documented return type Illuminate\Http\Response.
Loading history...
141
            ->route('admin.products.edit', $product->id)
0 ignored issues
show
Bug introduced by
$product->id of type integer is incompatible with the type array expected by parameter $parameters of Illuminate\Routing\Redirector::route(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

141
            ->route('admin.products.edit', /** @scrutinizer ignore-type */ $product->id)
Loading history...
142
            ->with('message', 'Create successful');
143
    }
144
145
    /**
146
     * Display the specified resource.
147
     *
148
     * @param  int $id
149
     * @return \Illuminate\Http\Response
150
     */
151
    public function show(int $id)
152
    {
153
        $product = $this->productRepo->findProductById($id);
154
        return view('admin.products.show', compact('product'));
0 ignored issues
show
Bug Best Practice introduced by
The expression return view('admin.produ...w', compact('product')) returns the type Illuminate\View\View which is incompatible with the documented return type Illuminate\Http\Response.
Loading history...
155
    }
156
157
    /**
158
     * Show the form for editing the specified resource.
159
     *
160
     * @param  int $id
161
     * @return \Illuminate\Http\Response
162
     */
163
    public function edit(int $id)
164
    {
165
        $product = $this->productRepo->findProductById($id);
166
        $productAttributes = $product->attributes()->get();
167
168
        $qty = $productAttributes->map(function ($item) {
169
            return $item->quantity;
170
        })->sum();
171
172
        if (request()->has('delete') && request()->has('pa')) {
173
            $pa = $productAttributes->where('id', request()->input('pa'))->first();
174
            $pa->attributesValues()->detach();
175
            $pa->delete();
176
177
            request()->session()->flash('message', 'Delete successful');
178
            return redirect()->route('admin.products.edit', [$product->id, 'combination' => 1]);
0 ignored issues
show
Bug Best Practice introduced by
The expression return redirect()->route...d, 'combination' => 1)) returns the type Illuminate\Http\RedirectResponse which is incompatible with the documented return type Illuminate\Http\Response.
Loading history...
179
        }
180
181
        $categories = $this->categoryRepo->listCategories('name', 'asc')
182
            ->where('parent_id', 1);
183
184
        return view('admin.products.edit', [
0 ignored issues
show
Bug Best Practice introduced by
The expression return view('admin.produ...andRepo->listBrands())) returns the type Illuminate\View\View which is incompatible with the documented return type Illuminate\Http\Response.
Loading history...
185
            'product' => $product,
186
            'images' => $product->images()->get(['src']),
187
            'categories' => $categories,
188
            'selectedIds' => $product->categories()->pluck('category_id')->all(),
189
            'attributes' => $this->attributeRepo->listAttributes(),
190
            'productAttributes' => $productAttributes,
191
            'qty' => $qty,
192
            'brands' => $this->brandRepo->listBrands()
193
        ]);
194
    }
195
196
    /**
197
     * Update the specified resource in storage.
198
     *
199
     * @param  UpdateProductRequest $request
200
     * @param  int $id
201
     * @return \Illuminate\Http\Response
202
     */
203
    public function update(UpdateProductRequest $request, int $id)
204
    {
205
        $product = $this->productRepo->findProductById($id);
206
207
        if ($request->has('attributeValue')) {
208
            $this->saveProductCombinations($request, $product);
209
            $request->session()->flash('message', 'Attribute combination created successful');
210
            return redirect()->route('admin.products.edit', [$id, 'combination' => 1]);
0 ignored issues
show
Bug Best Practice introduced by
The expression return redirect()->route...d, 'combination' => 1)) returns the type Illuminate\Http\RedirectResponse which is incompatible with the documented return type Illuminate\Http\Response.
Loading history...
211
        }
212
213
        $data = $request->except('categories', '_token', '_method');
214
        $data['slug'] = str_slug($request->input('name'));
215
216
        if ($request->hasFile('cover') && $request->file('cover') instanceof UploadedFile) {
217
            $data['cover'] = $this->productRepo->saveCoverImage($request->file('cover'));
218
        }
219
220
        $this->saveProductImages($request, $product);
221
222
        $this->productRepo->updateProduct($data, $id);
223
224
        if ($request->has('categories')) {
225
            $product->categories()->sync($request->input('categories'));
226
        } else {
227
            $product->categories()->detach();
228
        }
229
230
        return redirect()->route('admin.products.edit', $id)
0 ignored issues
show
Bug Best Practice introduced by
The expression return redirect()->route...', 'Update successful') returns the type Illuminate\Http\RedirectResponse which is incompatible with the documented return type Illuminate\Http\Response.
Loading history...
Bug introduced by
$id of type integer is incompatible with the type array expected by parameter $parameters of Illuminate\Routing\Redirector::route(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

230
        return redirect()->route('admin.products.edit', /** @scrutinizer ignore-type */ $id)
Loading history...
231
            ->with('message', 'Update successful');
232
    }
233
234
    /**
235
     * Remove the specified resource from storage.
236
     *
237
     * @param  int $id
238
     * @return \Illuminate\Http\Response
239
     */
240
    public function destroy($id)
241
    {
242
        $product = $this->productRepo->findProductById($id);
243
        $product->categories()->sync([]);
244
245
        $this->productRepo->delete($id);
246
247
        request()->session()->flash('message', 'Delete successful');
248
        return redirect()->route('admin.products.index');
0 ignored issues
show
Bug Best Practice introduced by
The expression return redirect()->route('admin.products.index') returns the type Illuminate\Http\RedirectResponse which is incompatible with the documented return type Illuminate\Http\Response.
Loading history...
249
    }
250
251
    /**
252
     * @param Request $request
253
     * @return \Illuminate\Http\RedirectResponse
254
     */
255
    public function removeImage(Request $request)
256
    {
257
        $this->productRepo->deleteFile($request->only('product', 'image'), 'uploads');
258
        request()->session()->flash('message', 'Image delete successful');
259
        return redirect()->back();
260
    }
261
262
    /**
263
     * @param Request $request
264
     * @return \Illuminate\Http\RedirectResponse
265
     */
266
    public function removeThumbnail(Request $request)
267
    {
268
        $this->productRepo->deleteThumb($request->input('src'));
269
        request()->session()->flash('message', 'Image delete successful');
270
        return redirect()->back();
271
    }
272
273
    /**
274
     * @param Request $request
275
     * @param Product $product
276
     */
277
    private function saveProductImages(Request $request, Product $product)
278
    {
279
        if ($request->hasFile('image')) {
280
            $this->productRepo->saveProductImages(collect($request->file('image')), $product);
281
        }
282
    }
283
284
    /**
285
     * @param Request $request
286
     * @param Product $product
287
     * @return boolean
288
     */
289
    private function saveProductCombinations(Request $request, Product $product)
290
    {
291
        $fields = $request->only('productAttributeQuantity', 'productAttributePrice');
292
293
        if ($errors = $this->validateFields($fields)) {
294
            return redirect()->route('admin.products.edit', [$product->id, 'combination' => 1])
0 ignored issues
show
Bug Best Practice introduced by
The expression return redirect()->route...))->withErrors($errors) returns the type Illuminate\Http\RedirectResponse which is incompatible with the documented return type boolean.
Loading history...
295
                ->withErrors($errors);
296
        }
297
298
        $quantity = $fields['productAttributeQuantity'];
299
        $price = $fields['productAttributePrice'];
300
301
        $attributeValues = $request->input('attributeValue');
302
        $productRepo = new ProductRepository($product);
303
        $productAttribute = $productRepo->saveProductAttributes(new ProductAttribute(compact('quantity', 'price')));
304
305
        // save the combinations
306
        return collect($attributeValues)->each(function ($attributeId) use ($productRepo, $productAttribute) {
0 ignored issues
show
Bug Best Practice introduced by
The expression return collect($attribut...{ /* ... */ })->count() returns the type integer which is incompatible with the documented return type boolean.
Loading history...
307
            $attribute = $this->attributeValueRepository->find($attributeId);
308
            return $productRepo->saveCombination($productAttribute, $attribute);
309
        })->count();
310
    }
311
312
    /**
313
     * @param array $data
314
     */
315
    private function validateFields(array $data)
316
    {
317
        $validator = Validator::make($data, [
318
            'productAttributeQuantity' => 'required'
319
        ]);
320
321
        if ($validator->fails()) {
322
            return $validator;
323
        }
324
    }
325
}
326