Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 42
0.00% covered (danger)
0.00%
0 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
AttributeController
0.00% covered (danger)
0.00%
0 / 42
0.00% covered (danger)
0.00%
0 / 6
110
0.00% covered (danger)
0.00%
0 / 1
 index
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 store
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
20
 update
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
2
 destroy
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 storeValueAjax
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
6
 destroyValueAjax
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace App\Http\Controllers\admin;
4
5use App\Http\Controllers\Controller;
6use App\Models\Attribute;
7use App\Models\AttributeValue;
8use Illuminate\Http\Request;
9use Illuminate\Support\Facades\DB;
10use Illuminate\Support\Facades\Log;
11use Illuminate\Validation\Rule;
12
13class AttributeController extends Controller
14{
15    /**
16     * Display a listing of all attributes with their values.
17     */
18    public function index()
19    {
20        $data['attributes'] = Attribute::with('values')->withCount('values')->orderBy('name')->get();
21
22        return view('admin.configuration.attribute')->with($data);
23    }
24
25    /**
26     * Store a newly created attribute (optionally with initial comma-separated values).
27     */
28    public function store(Request $request)
29    {
30        $request->validate([
31            'name' => 'required|string|max:100|unique:attributes,name',
32            'values' => 'nullable|string',
33        ]);
34
35        DB::beginTransaction();
36        try {
37            $attribute = Attribute::create(['name' => trim($request->name)]);
38
39            if ($request->filled('values')) {
40                $valueNames = array_filter(array_map('trim', explode(',', $request->values)));
41                foreach ($valueNames as $v) {
42                    $attribute->values()->firstOrCreate(['value' => $v]);
43                }
44            }
45
46            DB::commit();
47
48            return redirect()->route('admin.attribute.index')->with('success', 'Attribute created successfully.');
49        } catch (\Throwable $e) {
50            DB::rollBack();
51            Log::error('Attribute store failed: ' . $e->getMessage());
52
53            return redirect()->back()->withInput()->with('error', 'Could not create the attribute. Please try again.');
54        }
55    }
56
57    /**
58     * Rename an existing attribute.
59     */
60    public function update(Request $request, $id)
61    {
62        $attribute = Attribute::findOrFail($id);
63
64        $request->validate([
65            'name' => ['required', 'string', 'max:100', Rule::unique('attributes', 'name')->ignore($attribute->id)],
66        ]);
67
68        $attribute->update(['name' => trim($request->name)]);
69
70        return redirect()->route('admin.attribute.index')->with('success', 'Attribute renamed successfully.');
71    }
72
73    /**
74     * Delete an attribute. DB-level cascade (see the
75     * create_product_variations_and_attributes_tables migration) removes its
76     * values and any product-variation links to those values automatically.
77     */
78    public function destroy($id)
79    {
80        $attribute = Attribute::findOrFail($id);
81        $attribute->delete();
82
83        return redirect()->back()->with('success', 'Attribute deleted successfully.');
84    }
85
86    /**
87     * Add one or more comma-separated values to an existing attribute (AJAX).
88     * Reuses the same firstOrCreate-per-value approach as
89     * ProductController::storeAttributeAjax, just scoped to a known attribute id.
90     */
91    public function storeValueAjax(Request $request, $id)
92    {
93        $attribute = Attribute::findOrFail($id);
94
95        $request->validate([
96            'values' => 'required|string',
97        ]);
98
99        $valueNames = array_filter(array_map('trim', explode(',', $request->values)));
100        $saved = [];
101        foreach ($valueNames as $v) {
102            $saved[] = $attribute->values()->firstOrCreate(['value' => $v]);
103        }
104
105        return response()->json([
106            'success' => true,
107            'values' => $saved,
108        ]);
109    }
110
111    /**
112     * Delete a single attribute value (AJAX). DB-level cascade removes any
113     * product-variation links that used this value.
114     */
115    public function destroyValueAjax($valueId)
116    {
117        $value = AttributeValue::findOrFail($valueId);
118        $value->delete();
119
120        return response()->json(['success' => true]);
121    }
122}