Show.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602
  1. <?php
  2. namespace Dcat\Admin;
  3. use Dcat\Admin\Contracts\Repository;
  4. use Dcat\Admin\Show\Divider;
  5. use Dcat\Admin\Show\Field;
  6. use Dcat\Admin\Show\Newline;
  7. use Dcat\Admin\Show\Panel;
  8. use Dcat\Admin\Show\Relation;
  9. use Dcat\Admin\Traits\BuilderEvents;
  10. use Illuminate\Contracts\Support\Renderable;
  11. use Illuminate\Database\Eloquent\Model;
  12. use Illuminate\Support\Arr;
  13. use Illuminate\Support\Collection;
  14. use Illuminate\Support\Facades\URL;
  15. use Illuminate\Support\Fluent;
  16. use Illuminate\Support\Traits\Macroable;
  17. class Show implements Renderable
  18. {
  19. use BuilderEvents,
  20. Macroable {
  21. __call as macroCall;
  22. }
  23. /**
  24. * @var string
  25. */
  26. protected $view = 'admin::show';
  27. /**
  28. * @var Repository
  29. */
  30. protected $repository;
  31. /**
  32. * @var mixed
  33. */
  34. protected $_id;
  35. /**
  36. * @var Fluent
  37. */
  38. protected $model;
  39. /**
  40. * Show panel builder.
  41. *
  42. * @var callable
  43. */
  44. protected $builder;
  45. /**
  46. * Resource path for this show page.
  47. *
  48. * @var string
  49. */
  50. protected $resource;
  51. /**
  52. * Fields to be show.
  53. *
  54. * @var Collection
  55. */
  56. protected $fields;
  57. /**
  58. * Relations to be show.
  59. *
  60. * @var Collection
  61. */
  62. protected $relations;
  63. /**
  64. * @var Panel
  65. */
  66. protected $panel;
  67. /**
  68. * Show constructor.
  69. *
  70. * @param Model $model
  71. * @param mixed $builder
  72. */
  73. public function __construct(Repository $repository, $builder = null)
  74. {
  75. $this->repository = Admin::createRepository($repository);
  76. $this->builder = $builder;
  77. $this->initPanel();
  78. $this->initContents();
  79. $this->callResolving();
  80. }
  81. /**
  82. * Create a show instance.
  83. *
  84. * @param mixed ...$params
  85. * @return $this
  86. */
  87. public static function make(...$params)
  88. {
  89. return new static(...$params);
  90. }
  91. /**
  92. * Get primary key name of model.
  93. *
  94. * @return string
  95. */
  96. public function getKeyName()
  97. {
  98. return $this->repository->getKeyName();
  99. }
  100. /**
  101. * @param mixed $id
  102. */
  103. public function setId($id)
  104. {
  105. $this->_id = $id;
  106. }
  107. /**
  108. * @return mixed
  109. */
  110. public function getId()
  111. {
  112. return $this->_id;
  113. }
  114. /**
  115. * @param $model
  116. */
  117. public function setModel(Fluent $model)
  118. {
  119. $this->model = $model;
  120. }
  121. /**
  122. * @return Fluent
  123. */
  124. public function getModel()
  125. {
  126. if (!$this->model) {
  127. $this->setModel(new Fluent($this->repository->detail($this)));
  128. }
  129. return $this->model;
  130. }
  131. /**
  132. * Set a view to render.
  133. *
  134. * @param string $view
  135. * @param array $variables
  136. * @return $this
  137. */
  138. public function setView($view, $variables = [])
  139. {
  140. if (!empty($variables)) {
  141. $this->with($variables);
  142. }
  143. $this->panel->setView($view);
  144. return $this;
  145. }
  146. /**
  147. * Add variables to show view.
  148. *
  149. * @param array $variables
  150. * @return $this
  151. */
  152. public function with($variables = [])
  153. {
  154. $this->panel->with($variables);
  155. return $this;
  156. }
  157. /**
  158. * @return $this
  159. */
  160. public function wrap(\Closure $wrapper)
  161. {
  162. $this->panel->wrap($wrapper);
  163. return $this;
  164. }
  165. /**
  166. * Initialize the contents to show.
  167. */
  168. protected function initContents()
  169. {
  170. $this->fields = new Collection();
  171. $this->relations = new Collection();
  172. }
  173. /**
  174. * Initialize panel.
  175. */
  176. protected function initPanel()
  177. {
  178. $this->panel = new Panel($this);
  179. }
  180. /**
  181. * Get panel instance.
  182. *
  183. * @return Panel
  184. */
  185. public function panel()
  186. {
  187. return $this->panel;
  188. }
  189. /**
  190. * Add a model field to show.
  191. *
  192. * @param string $name
  193. * @param string $label
  194. *
  195. * @return Field
  196. */
  197. public function field($name, $label = '')
  198. {
  199. return $this->addField($name, $label);
  200. }
  201. /**
  202. * Add multiple fields.
  203. *
  204. * @param array $fields
  205. *
  206. * @return $this
  207. */
  208. public function fields(array $fields = [])
  209. {
  210. if (!Arr::isAssoc($fields)) {
  211. $fields = array_combine($fields, $fields);
  212. }
  213. foreach ($fields as $field => $label) {
  214. $this->field($field, $label);
  215. }
  216. return $this;
  217. }
  218. /**
  219. * @return Collection
  220. */
  221. public function getFields()
  222. {
  223. return $this->fields;
  224. }
  225. /**
  226. * @return Collection
  227. */
  228. public function getRelations()
  229. {
  230. return $this->relations;
  231. }
  232. /**
  233. * Show all fields.
  234. *
  235. * @return Show
  236. */
  237. public function all()
  238. {
  239. $fields = array_keys($this->getModel()->toArray());
  240. return $this->fields($fields);
  241. }
  242. /**
  243. * Add a relation to show.
  244. *
  245. * @param string $name
  246. * @param string|\Closure $label
  247. * @param null|\Closure $builder
  248. *
  249. * @return Relation
  250. */
  251. public function relation($name, $label, $builder = null)
  252. {
  253. if (is_null($builder)) {
  254. $builder = $label;
  255. $label = '';
  256. }
  257. return $this->addRelation($name, $builder, $label);
  258. }
  259. /**
  260. * Add a model field to show.
  261. *
  262. * @param string $name
  263. * @param string $label
  264. *
  265. * @return Field
  266. */
  267. protected function addField($name, $label = '')
  268. {
  269. $field = new Field($name, $label);
  270. $field->setParent($this);
  271. $this->overwriteExistingField($name);
  272. $this->fields->push($field);
  273. return $field;
  274. }
  275. /**
  276. * Add a relation panel to show.
  277. *
  278. * @param string $name
  279. * @param \Closure $builder
  280. * @param string $label
  281. *
  282. * @return Relation
  283. */
  284. protected function addRelation($name, $builder, $label = '')
  285. {
  286. $relation = new Relation($name, $builder, $label);
  287. $relation->setParent($this);
  288. $this->overwriteExistingRelation($name);
  289. $this->relations->push($relation);
  290. return $relation;
  291. }
  292. /**
  293. * Overwrite existing field.
  294. *
  295. * @param string $name
  296. */
  297. protected function overwriteExistingField($name)
  298. {
  299. if ($this->fields->isEmpty()) {
  300. return;
  301. }
  302. $this->fields = $this->fields->filter(
  303. function (Field $field) use ($name) {
  304. return $field->getName() != $name;
  305. }
  306. );
  307. }
  308. /**
  309. * Overwrite existing relation.
  310. *
  311. * @param string $name
  312. */
  313. protected function overwriteExistingRelation($name)
  314. {
  315. if ($this->relations->isEmpty()) {
  316. return;
  317. }
  318. $this->relations = $this->relations->filter(
  319. function (Relation $relation) use ($name) {
  320. return $relation->getName() != $name;
  321. }
  322. );
  323. }
  324. /**
  325. * @return Repository
  326. */
  327. public function getRepository(): Repository
  328. {
  329. return $this->repository;
  330. }
  331. /**
  332. * Show a divider.
  333. */
  334. public function divider()
  335. {
  336. $this->fields->push(new Divider());
  337. }
  338. /**
  339. * Show a divider.
  340. */
  341. public function newline()
  342. {
  343. $this->fields->push(new Newline());
  344. }
  345. /**
  346. * Disable `list` tool.
  347. *
  348. * @return $this
  349. */
  350. public function disableListButton(bool $disable = true)
  351. {
  352. $this->panel->getTools()->disableList($disable);
  353. return $this;
  354. }
  355. /**
  356. * Disable `delete` tool.
  357. *
  358. * @return $this
  359. */
  360. public function disableDeleteButton(bool $disable = true)
  361. {
  362. $this->panel->getTools()->disableDelete($disable);
  363. return $this;
  364. }
  365. /**
  366. * Disable `edit` tool.
  367. *
  368. * @return $this
  369. */
  370. public function disableEditButton(bool $disable = true)
  371. {
  372. $this->panel->getTools()->disableEdit($disable);
  373. return $this;
  374. }
  375. /**
  376. * Show quick edit tool.
  377. *
  378. * @param null|string $width
  379. * @param null|string $height
  380. * @return $this
  381. */
  382. public function showQuickEdit(?string $width = null, ?string $height = null)
  383. {
  384. $this->panel->getTools()->showQuickEdit($width, $height);
  385. return $this;
  386. }
  387. /**
  388. * Disable quick edit tool.
  389. *
  390. * @return $this
  391. */
  392. public function disableQuickEdit()
  393. {
  394. $this->panel->getTools()->disableQuickEdit();
  395. return $this;
  396. }
  397. /**
  398. * Set resource path.
  399. *
  400. * @param string $resource
  401. *
  402. * @return $this
  403. */
  404. public function resource(string $resource)
  405. {
  406. if ($resource) {
  407. $this->resource = admin_url($resource);
  408. }
  409. return $this;
  410. }
  411. /**
  412. * Get resource path.
  413. *
  414. * @return string
  415. */
  416. public function getResource()
  417. {
  418. if (empty($this->resource)) {
  419. $path = request()->path();
  420. $segments = explode('/', $path);
  421. array_pop($segments);
  422. $this->resource = url(implode('/', $segments));
  423. }
  424. return $this->resource;
  425. }
  426. /**
  427. * Add field and relation dynamically.
  428. *
  429. * @param string $method
  430. * @param array $arguments
  431. *
  432. * @return Field
  433. */
  434. public function __call($method, $arguments = [])
  435. {
  436. if (static::hasMacro($method)) {
  437. return $this->macroCall($method, $arguments);
  438. }
  439. return $this->call($method, $arguments);
  440. }
  441. /**
  442. * @param $method
  443. * @param array $arguments
  444. * @return bool|Show|Field|Relation
  445. */
  446. protected function call($method, $arguments = [])
  447. {
  448. $label = isset($arguments[0]) ? $arguments[0] : '';
  449. if ($field = $this->handleRelationField($method, $arguments)) {
  450. return $field;
  451. }
  452. return $this->addField($method, $label);
  453. }
  454. /**
  455. * Handle relation field.
  456. *
  457. * @param string $method
  458. * @param array $arguments
  459. *
  460. * @return $this|bool|Relation|Field
  461. */
  462. protected function handleRelationField($method, $arguments)
  463. {
  464. if (count($arguments) == 1 && $arguments[0] instanceof \Closure) {
  465. return $this->addRelation($method, $arguments[0]);
  466. } elseif (count($arguments) == 2 && $arguments[1] instanceof \Closure) {
  467. return $this->addRelation($method, $arguments[1], $arguments[0]);
  468. }
  469. return false;
  470. }
  471. /**
  472. * Render the show panels.
  473. *
  474. * @return string
  475. */
  476. public function render()
  477. {
  478. try {
  479. $model = $this->getModel();
  480. if (is_callable($this->builder)) {
  481. call_user_func($this->builder, $this);
  482. }
  483. if ($this->fields->isEmpty()) {
  484. $this->all();
  485. }
  486. if (is_array($this->builder)) {
  487. $this->fields($this->builder);
  488. }
  489. $this->fields->each->setValue($model);
  490. $this->relations->each->setModel($model);
  491. $this->callComposing();
  492. $data = [
  493. 'panel' => $this->panel->fill($this->fields),
  494. 'relations' => $this->relations,
  495. ];
  496. return view($this->view, $data)->render();
  497. } catch (\Throwable $e) {
  498. return Admin::makeExceptionHandler()->renderException($e);
  499. }
  500. }
  501. /**
  502. * Add a model field to show.
  503. *
  504. * @param string $name
  505. * @return Field|Collection
  506. */
  507. public function __get($name)
  508. {
  509. return $this->call($name);
  510. }
  511. }