Show.php 12 KB

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