FrontMenuController.php 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. <?php
  2. namespace Longyi\FrontMenu\Http\Controllers;
  3. use Illuminate\Http\Request;
  4. use Illuminate\Routing\Controller;
  5. use Longyi\FrontMenu\Models\FrontMenuItem;
  6. use Longyi\FrontMenu\Repositories\FrontMenuItemRepository;
  7. class FrontMenuController extends Controller
  8. {
  9. protected $repository;
  10. public function __construct(FrontMenuItemRepository $repository)
  11. {
  12. $this->repository = $repository;
  13. $this->_config = request('_config');
  14. }
  15. /**
  16. * Display the menu tree list.
  17. */
  18. public function index()
  19. {
  20. $menuItems = $this->repository->getMenuTree();
  21. return view($this->_config['view'], compact('menuItems'));
  22. }
  23. /**
  24. * Show the create form.
  25. */
  26. public function create()
  27. {
  28. $menuItems = $this->repository->getMenuTree();
  29. return view($this->_config['view'], compact('menuItems'));
  30. }
  31. /**
  32. * Store a new menu item.
  33. */
  34. public function store(Request $request)
  35. {
  36. $request->validate([
  37. 'name' => 'required|string|max:255',
  38. 'slug' => 'required|string|max:255|unique:front_menu_items,slug',
  39. 'url' => 'nullable|string|max:2048',
  40. 'image' => 'nullable|string|max:2048',
  41. 'banner' => 'nullable|string|max:2048',
  42. 'wap_image' => 'nullable|string|max:2048',
  43. 'wap_banner' => 'nullable|string|max:2048',
  44. 'show_icon' => 'nullable|boolean',
  45. 'parent_id' => 'nullable|exists:front_menu_items,id',
  46. 'sort_order' => 'nullable|integer',
  47. 'status' => 'nullable|boolean',
  48. ]);
  49. $this->repository->create($this->prepareData($request));
  50. session()->flash('success', __('frontmenu::app.admin.menu.created'));
  51. return redirect()->route($this->_config['redirect']);
  52. }
  53. /**
  54. * Show the edit form.
  55. */
  56. public function edit($id)
  57. {
  58. $menuItem = $this->repository->findOrFail($id);
  59. $menuItems = $this->repository->getMenuTree();
  60. return view($this->_config['view'], compact('menuItem', 'menuItems'));
  61. }
  62. /**
  63. * Update an existing menu item.
  64. */
  65. public function update(Request $request, $id)
  66. {
  67. $request->validate([
  68. 'name' => 'required|string|max:255',
  69. 'slug' => 'required|string|max:255|unique:front_menu_items,slug,' . $id,
  70. 'url' => 'nullable|string|max:2048',
  71. 'image' => 'nullable|string|max:2048',
  72. 'banner' => 'nullable|string|max:2048',
  73. 'wap_image' => 'nullable|string|max:2048',
  74. 'wap_banner' => 'nullable|string|max:2048',
  75. 'show_icon' => 'nullable|boolean',
  76. 'parent_id' => 'nullable|exists:front_menu_items,id',
  77. 'sort_order' => 'nullable|integer',
  78. 'status' => 'nullable|boolean',
  79. ]);
  80. // Prevent a menu item from becoming its own parent or a descendant's child.
  81. if ($request->filled('parent_id') && $request->input('parent_id') == $id) {
  82. session()->flash('error', __('frontmenu::app.admin.menu.self-parent'));
  83. return redirect()->back()->withInput();
  84. }
  85. $this->repository->update($this->prepareData($request), $id);
  86. session()->flash('success', __('frontmenu::app.admin.menu.updated'));
  87. return redirect()->route($this->_config['redirect']);
  88. }
  89. /**
  90. * Delete a menu item (and its children via cascade).
  91. */
  92. public function destroy($id)
  93. {
  94. $menuItem = $this->repository->findOrFail($id);
  95. $menuItem->delete();
  96. session()->flash('success', __('frontmenu::app.admin.menu.deleted'));
  97. return redirect()->route($this->_config['redirect']);
  98. }
  99. /**
  100. * Reorder menu items via drag & drop.
  101. */
  102. public function reorder(Request $request)
  103. {
  104. $request->validate([
  105. 'items' => 'required|array',
  106. 'items.*.id' => 'required|integer|exists:front_menu_items,id',
  107. ]);
  108. $items = $request->input('items', []);
  109. // Group by parent so each level gets its own sort order sequence.
  110. $grouped = [];
  111. foreach ($items as $item) {
  112. $parentId = $item['parent_id'] ?? null;
  113. $grouped[$parentId ?? 'root'][] = $item['id'];
  114. }
  115. foreach ($grouped as $parentKey => $ids) {
  116. $parentId = $parentKey === 'root' ? null : $parentKey;
  117. foreach ($ids as $index => $id) {
  118. FrontMenuItem::query()->where('id', $id)->update([
  119. 'parent_id' => $parentId,
  120. 'sort_order' => $index,
  121. ]);
  122. }
  123. }
  124. return response()->json([
  125. 'success' => true,
  126. 'message' => __('frontmenu::app.admin.menu.reordered'),
  127. ]);
  128. }
  129. /**
  130. * Normalize request data before persisting.
  131. */
  132. protected function prepareData(Request $request): array
  133. {
  134. $data = $request->only([
  135. 'name',
  136. 'slug',
  137. 'url',
  138. 'image',
  139. 'banner',
  140. 'wap_image',
  141. 'wap_banner',
  142. 'parent_id',
  143. 'sort_order',
  144. ]);
  145. $data['parent_id'] = $request->filled('parent_id') ? (int) $request->input('parent_id') : null;
  146. $data['sort_order'] = $request->input('sort_order', 0);
  147. $data['status'] = $request->has('status') ? (bool) $request->input('status') : true;
  148. $data['show_icon'] = $request->has('show_icon') ? (bool) $request->input('show_icon') : false;
  149. $data['created_by'] = auth()->guard('admin')->user()->id ?? null;
  150. return $data;
  151. }
  152. }