EloquentRepository.php 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952
  1. <?php
  2. namespace Dcat\Admin\Repositories;
  3. use Dcat\Admin\Contracts\TreeRepository;
  4. use Dcat\Admin\Exception\AdminException;
  5. use Dcat\Admin\Exception\RuntimeException;
  6. use Dcat\Admin\Form;
  7. use Dcat\Admin\Grid;
  8. use Dcat\Admin\Show;
  9. use Dcat\Laravel\Database\SoftDeletes as DcatSoftDeletes;
  10. use Illuminate\Database\Eloquent\Builder;
  11. use Illuminate\Database\Eloquent\Model as EloquentModel;
  12. use Illuminate\Database\Eloquent\Relations;
  13. use Illuminate\Database\Eloquent\Relations\BelongsTo;
  14. use Illuminate\Database\Eloquent\Relations\HasOne;
  15. use Illuminate\Database\Eloquent\Relations\Relation;
  16. use Illuminate\Database\Eloquent\SoftDeletes;
  17. use Illuminate\Support\Arr;
  18. use Illuminate\Support\Collection;
  19. use Illuminate\Support\Facades\DB;
  20. use Illuminate\Support\Str;
  21. use Spatie\EloquentSortable\Sortable;
  22. class EloquentRepository extends Repository implements TreeRepository
  23. {
  24. /**
  25. * @var string
  26. */
  27. protected $eloquentClass;
  28. /**
  29. * @var EloquentModel
  30. */
  31. protected $model;
  32. /**
  33. * @var Builder
  34. */
  35. protected $queryBuilder;
  36. /**
  37. * @var array
  38. */
  39. protected $relations = [];
  40. /**
  41. * @var \Illuminate\Database\Eloquent\Collection
  42. */
  43. protected $collection;
  44. /**
  45. * EloquentRepository constructor.
  46. *
  47. * @param EloquentModel|array|string $modelOrRelations $modelOrRelations
  48. */
  49. public function __construct($modelOrRelations = [])
  50. {
  51. $this->initModel($modelOrRelations);
  52. }
  53. /**
  54. * 初始化模型.
  55. *
  56. * @param EloquentModel|Builder|array|string $modelOrRelations
  57. */
  58. protected function initModel($modelOrRelations)
  59. {
  60. if (is_string($modelOrRelations) && class_exists($modelOrRelations)) {
  61. $this->eloquentClass = $modelOrRelations;
  62. } elseif ($modelOrRelations instanceof EloquentModel) {
  63. $this->eloquentClass = get_class($modelOrRelations);
  64. $this->model = $modelOrRelations;
  65. } elseif ($modelOrRelations instanceof Builder) {
  66. $this->model = $modelOrRelations->getModel();
  67. $this->eloquentClass = get_class($this->model);
  68. $this->queryBuilder = $modelOrRelations;
  69. } else {
  70. $this->setRelations($modelOrRelations);
  71. }
  72. $this->setKeyName($this->model()->getKeyName());
  73. $traits = class_uses($this->model());
  74. $this->setIsSoftDeletes(
  75. in_array(SoftDeletes::class, $traits, true)
  76. || in_array(DcatSoftDeletes::class, $traits, true)
  77. );
  78. }
  79. /**
  80. * @return string
  81. */
  82. public function getCreatedAtColumn()
  83. {
  84. return $this->model()->getCreatedAtColumn();
  85. }
  86. /**
  87. * @return string
  88. */
  89. public function getUpdatedAtColumn()
  90. {
  91. return $this->model()->getUpdatedAtColumn();
  92. }
  93. /**
  94. * 获取列表页面查询的字段.
  95. *
  96. * @return array
  97. */
  98. public function getGridColumns()
  99. {
  100. return ['*'];
  101. }
  102. /**
  103. * 获取表单页面查询的字段.
  104. *
  105. * @return array
  106. */
  107. public function getFormColumns()
  108. {
  109. return ['*'];
  110. }
  111. /**
  112. * 获取详情页面查询的字段.
  113. *
  114. * @return array
  115. */
  116. public function getDetailColumns()
  117. {
  118. return ['*'];
  119. }
  120. /**
  121. * 设置关联关系.
  122. *
  123. * @param mixed $relations
  124. *
  125. * @return $this
  126. */
  127. public function setRelations($relations)
  128. {
  129. $this->relations = (array) $relations;
  130. return $this;
  131. }
  132. /**
  133. * 查询Grid表格数据.
  134. *
  135. * @param Grid\Model $model
  136. *
  137. * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator|Collection|array
  138. */
  139. public function get(Grid\Model $model)
  140. {
  141. $this->setSort($model);
  142. $this->setPaginate($model);
  143. $query = $this->newQuery();
  144. if ($this->relations) {
  145. $query->with($this->relations);
  146. }
  147. $model->getQueries()->unique()->each(function ($value) use (&$query) {
  148. if ($value['method'] === 'paginate') {
  149. $value['arguments'][1] = $this->getGridColumns();
  150. } elseif ($value['method'] === 'get') {
  151. $value['arguments'] = [$this->getGridColumns()];
  152. }
  153. $query = call_user_func_array([$query, $value['method']], $value['arguments'] ?? []);
  154. });
  155. return $query;
  156. }
  157. /**
  158. * 设置表格数据排序.
  159. *
  160. * @param Grid\Model $model
  161. *
  162. * @return void
  163. */
  164. protected function setSort(Grid\Model $model)
  165. {
  166. [$column, $type, $cast] = $model->getSort();
  167. if (empty($column) || empty($type)) {
  168. $orders = $model->findQueryByMethod('orderBy')->merge($model->findQueryByMethod('orderByDesc'));
  169. $model->resetOrderBy();
  170. $orders->each(function ($orderBy) use ($model) {
  171. $column = $orderBy['arguments'][0];
  172. $type = $orderBy['method'] === 'orderByDesc' ? 'desc' : ($orderBy['arguments'][1] ?? 'asc');
  173. $cast = null;
  174. $this->addOrderBy($model, $column, $type, $cast);
  175. });
  176. return;
  177. }
  178. $model->resetOrderBy();
  179. $this->addOrderBy($model, $column, $type, $cast);
  180. }
  181. /**
  182. * @param Grid\Model $model
  183. * @param string $column
  184. * @param string $type
  185. * @param string $cast
  186. *
  187. * @throws \Exception
  188. */
  189. protected function addOrderBy(Grid\Model $model, $column, $type, $cast)
  190. {
  191. $explodedCols = explode('.', $column);
  192. $isRelation = empty($explodedCols[1]) ? false : method_exists($this->model(), $explodedCols[0]);
  193. if (count($explodedCols) > 1 && $isRelation) {
  194. $this->setRelationSort($model, $column, $type, $cast);
  195. return;
  196. }
  197. $this->setOrderBy(
  198. $model,
  199. str_replace('.', '->', $column),
  200. $type,
  201. $cast);
  202. }
  203. /**
  204. * @param Grid\Model $model
  205. * @param $column
  206. * @param $type
  207. *
  208. * @param $cast
  209. */
  210. protected function setOrderBy(Grid\Model $model, $column, $type, $cast)
  211. {
  212. $isJsonColumn = Str::contains($column, '->');
  213. if ($isJsonColumn) {
  214. $explodedCols = explode('->', $column);
  215. // json字段排序
  216. $col = $this->wrapMySqlColumn(array_shift($explodedCols));
  217. $parts = implode('.', $explodedCols);
  218. $column = "JSON_UNQUOTE(JSON_EXTRACT({$col}, '$.{$parts}'))";
  219. }
  220. if (! empty($cast)) {
  221. $column = $this->wrapMySqlColumn($column);
  222. $model->addQuery(
  223. 'orderByRaw',
  224. ["CAST({$column} AS {$cast}) {$type}"]
  225. );
  226. return;
  227. }
  228. if ($isJsonColumn) {
  229. $model->addQuery('orderByRaw', ["{$column} {$type}"]);
  230. } else {
  231. $model->addQuery('orderBy', [$column, $type]);
  232. }
  233. }
  234. /**
  235. * @param string $column
  236. *
  237. * @return string
  238. */
  239. protected function wrapMySqlColumn($column)
  240. {
  241. if (Str::contains($column, '`')) {
  242. return $column;
  243. }
  244. $columns = explode('.', $column);
  245. foreach ($columns as &$column) {
  246. if (! Str::contains($column, '`')) {
  247. $column = "`{$column}`";
  248. }
  249. }
  250. return implode('.', $columns);
  251. }
  252. /**
  253. * 设置关联数据排序.
  254. *
  255. * @param Grid\Model $model
  256. * @param string $column
  257. * @param string $type
  258. * @param string $cast
  259. *
  260. * @throws \Exception
  261. */
  262. protected function setRelationSort(Grid\Model $model, $column, $type, $cast)
  263. {
  264. [$relationName, $relationColumn] = explode('.', $column, 2);
  265. $relation = $this->model()->$relationName();
  266. $model->addQuery('select', [$this->model()->getTable().'.*']);
  267. $model->addQuery('join', $this->joinParameters($relation));
  268. $this->setOrderBy(
  269. $model,
  270. $relation->getRelated()->getTable().'.'.str_replace('.', '->', $relationColumn),
  271. $type,
  272. $cast
  273. );
  274. }
  275. /**
  276. * 关联模型 join 连接查询.
  277. *
  278. * @param Relation $relation
  279. *
  280. * @throws \Exception
  281. *
  282. * @return array
  283. */
  284. protected function joinParameters(Relation $relation)
  285. {
  286. $relatedTable = $relation->getRelated()->getTable();
  287. if ($relation instanceof BelongsTo) {
  288. $foreignKeyMethod = version_compare(app()->version(), '5.8.0', '<') ? 'getForeignKey' : 'getForeignKeyName';
  289. return [
  290. $relatedTable,
  291. $relation->{$foreignKeyMethod}(),
  292. '=',
  293. $relatedTable.'.'.$relation->getRelated()->getKeyName(),
  294. ];
  295. }
  296. if ($relation instanceof HasOne) {
  297. return [
  298. $relatedTable,
  299. $relation->getQualifiedParentKeyName(),
  300. '=',
  301. $relation->getQualifiedForeignKeyName(),
  302. ];
  303. }
  304. throw new AdminException('Related sortable only support `HasOne` and `BelongsTo` relation.');
  305. }
  306. /**
  307. * 设置分页参数.
  308. *
  309. * @param Grid\Model $model
  310. *
  311. * @return void
  312. */
  313. protected function setPaginate(Grid\Model $model)
  314. {
  315. $paginate = $model->findQueryByMethod('paginate')->first();
  316. $model->rejectQuery(['paginate']);
  317. if (! $model->allowPagination()) {
  318. $model->addQuery('get', [$this->getGridColumns()]);
  319. } else {
  320. $model->addQuery('paginate', $this->resolvePerPage($model, $paginate));
  321. }
  322. }
  323. /**
  324. * 获取分页参数.
  325. *
  326. * @param Grid\Model $model
  327. * @param array|null $paginate
  328. *
  329. * @return array
  330. */
  331. protected function resolvePerPage(Grid\Model $model, $paginate)
  332. {
  333. if ($paginate && is_array($paginate)) {
  334. if ($perPage = request()->input($model->getPerPageName())) {
  335. $paginate['arguments'][0] = (int) $perPage;
  336. }
  337. return $paginate['arguments'];
  338. }
  339. return [
  340. $model->getPerPage(),
  341. $this->getGridColumns(),
  342. $model->getPageName(),
  343. $model->getCurrentPage(),
  344. ];
  345. }
  346. /**
  347. * 查询编辑页面数据.
  348. *
  349. * @param Form $form
  350. *
  351. * @return array|\Illuminate\Contracts\Support\Arrayable
  352. */
  353. public function edit(Form $form)
  354. {
  355. $query = $this->newQuery();
  356. if ($this->isSoftDeletes) {
  357. $query->withTrashed();
  358. }
  359. $this->model = $query
  360. ->with($this->getRelations())
  361. ->findOrFail($form->getKey(), $this->getFormColumns());
  362. return $this->model;
  363. }
  364. /**
  365. * 查询详情页面数据.
  366. *
  367. * @param Show $show
  368. *
  369. * @return array|\Illuminate\Contracts\Support\Arrayable
  370. */
  371. public function detail(Show $show)
  372. {
  373. $query = $this->newQuery();
  374. if ($this->isSoftDeletes) {
  375. $query->withTrashed();
  376. }
  377. $this->model = $query
  378. ->with($this->getRelations())
  379. ->findOrFail($show->getKey(), $this->getDetailColumns());
  380. return $this->model;
  381. }
  382. /**
  383. * 新增记录.
  384. *
  385. * @param Form $form
  386. *
  387. * @return mixed
  388. */
  389. public function store(Form $form)
  390. {
  391. $result = null;
  392. DB::transaction(function () use ($form, &$result) {
  393. $model = $this->model();
  394. $updates = $form->updates();
  395. [$relations, $relationKeyMap] = $this->getRelationInputs($model, $updates);
  396. if ($relations) {
  397. $updates = Arr::except($updates, array_keys($relationKeyMap));
  398. }
  399. foreach ($updates as $column => $value) {
  400. $model->setAttribute($column, $value);
  401. }
  402. $result = $model->save();
  403. $this->updateRelation($form, $model, $relations, $relationKeyMap);
  404. });
  405. return $this->model()->getKey();
  406. }
  407. /**
  408. * 查询更新前的行数据.
  409. *
  410. * @param Form $form
  411. *
  412. * @return array|\Illuminate\Contracts\Support\Arrayable
  413. */
  414. public function updating(Form $form)
  415. {
  416. return $this->edit($form);
  417. }
  418. /**
  419. * 更新数据.
  420. *
  421. * @param Form $form
  422. *
  423. * @return bool
  424. */
  425. public function update(Form $form)
  426. {
  427. /* @var EloquentModel $builder */
  428. $model = $this->model();
  429. if (! $model->getKey()) {
  430. $model->exists = true;
  431. $model->setAttribute($model->getKeyName(), $form->getKey());
  432. }
  433. $result = null;
  434. DB::transaction(function () use ($form, $model, &$result) {
  435. $updates = $form->updates();
  436. [$relations, $relationKeyMap] = $this->getRelationInputs($model, $updates);
  437. if ($relations) {
  438. $updates = Arr::except($updates, array_keys($relationKeyMap));
  439. }
  440. foreach ($updates as $column => $value) {
  441. /* @var EloquentModel $model */
  442. $model->setAttribute($column, $value);
  443. }
  444. $result = $model->update();
  445. $this->updateRelation($form, $model, $relations, $relationKeyMap);
  446. });
  447. return $result;
  448. }
  449. /**
  450. * 数据行排序上移一个单位.
  451. *
  452. * @return bool
  453. */
  454. public function moveOrderUp()
  455. {
  456. $model = $this->model();
  457. if (! $model instanceof Sortable) {
  458. throw new RuntimeException(
  459. sprintf(
  460. 'The model "%s" must be a type of %s.',
  461. get_class($model),
  462. Sortable::class
  463. )
  464. );
  465. }
  466. return $model->moveOrderUp() ? true : false;
  467. }
  468. /**
  469. * 数据行排序下移一个单位.
  470. *
  471. * @return bool
  472. */
  473. public function moveOrderDown()
  474. {
  475. $model = $this->model();
  476. if (! $model instanceof Sortable) {
  477. throw new RuntimeException(
  478. sprintf(
  479. 'The model "%s" must be a type of %s.',
  480. get_class($model),
  481. Sortable::class
  482. )
  483. );
  484. }
  485. return $model->moveOrderDown() ? true : false;
  486. }
  487. /**
  488. * 删除数据.
  489. *
  490. * @param Form $form
  491. * @param array $originalData
  492. *
  493. * @return bool
  494. */
  495. public function delete(Form $form, array $originalData)
  496. {
  497. $models = $this->collection->keyBy($this->getKeyName());
  498. collect(explode(',', $form->getKey()))->filter()->each(function ($id) use ($form, $models) {
  499. $model = $models->get($id);
  500. if (! $model) {
  501. return;
  502. }
  503. $data = $model->toArray();
  504. if ($this->isSoftDeletes && $model->trashed()) {
  505. $form->deleteFiles($data, true);
  506. $model->forceDelete();
  507. return;
  508. } elseif (! $this->isSoftDeletes) {
  509. $form->deleteFiles($data);
  510. }
  511. $model->delete();
  512. });
  513. return true;
  514. }
  515. /**
  516. * 查询删除前的行数据.
  517. *
  518. * @param Form $form
  519. *
  520. * @return array
  521. */
  522. public function deleting(Form $form)
  523. {
  524. $query = $this->newQuery();
  525. if ($this->isSoftDeletes) {
  526. $query->withTrashed();
  527. }
  528. $id = $form->getKey();
  529. $this->collection = $query
  530. ->with($this->getRelations())
  531. ->findOrFail(
  532. collect(explode(',', $id))->filter()->toArray(),
  533. $this->getFormColumns()
  534. );
  535. return $this->collection->toArray();
  536. }
  537. /**
  538. * 获取父级ID字段名称.
  539. *
  540. * @return string
  541. */
  542. public function getParentColumn()
  543. {
  544. $model = $this->model();
  545. if (method_exists($model, 'getParentColumn')) {
  546. return $model->getParentColumn();
  547. }
  548. }
  549. /**
  550. * 获取标题字段名称.
  551. *
  552. * @return string
  553. */
  554. public function getTitleColumn()
  555. {
  556. $model = $this->model();
  557. if (method_exists($model, 'getTitleColumn')) {
  558. return $model->getTitleColumn();
  559. }
  560. }
  561. /**
  562. * 获取排序字段名称.
  563. *
  564. * @return string
  565. */
  566. public function getOrderColumn()
  567. {
  568. $model = $this->model();
  569. if (method_exists($model, 'getOrderColumn')) {
  570. return $model->getOrderColumn();
  571. }
  572. }
  573. /**
  574. * 保存层级数据排序.
  575. *
  576. * @param array $tree
  577. * @param int $parentId
  578. */
  579. public function saveOrder($tree = [], $parentId = 0)
  580. {
  581. $this->model()->saveOrder($tree, $parentId);
  582. }
  583. /**
  584. * 设置数据查询回调.
  585. *
  586. * @param \Closure|null $query
  587. *
  588. * @return $this
  589. */
  590. public function withQuery($queryCallback)
  591. {
  592. $this->model()->withQuery($queryCallback);
  593. return $this;
  594. }
  595. /**
  596. * 获取层级数据.
  597. *
  598. * @return array
  599. */
  600. public function toTree()
  601. {
  602. if ($this->relations) {
  603. $this->withQuery(function ($model) {
  604. return $model->with($this->relations);
  605. });
  606. }
  607. return $this->model()->toTree();
  608. }
  609. /**
  610. * @return Builder
  611. */
  612. protected function newQuery()
  613. {
  614. if ($this->queryBuilder) {
  615. return clone $this->queryBuilder;
  616. }
  617. return $this->model()->newQuery();
  618. }
  619. /**
  620. * 获取model对象.
  621. *
  622. * @return EloquentModel
  623. */
  624. public function model()
  625. {
  626. return $this->model ?: ($this->model = $this->createModel());
  627. }
  628. /**
  629. * @param array $data
  630. *
  631. * @return EloquentModel
  632. */
  633. public function createModel(array $data = [])
  634. {
  635. $model = new $this->eloquentClass();
  636. if ($data) {
  637. $model->setRawAttributes($data);
  638. }
  639. return $model;
  640. }
  641. /**
  642. * @param array $relations
  643. *
  644. * @return $this
  645. */
  646. public static function with($relations = [])
  647. {
  648. return (new static())->setRelations($relations);
  649. }
  650. /**
  651. * 获取模型的所有关联关系.
  652. *
  653. * @return array
  654. */
  655. public function getRelations()
  656. {
  657. return $this->relations;
  658. }
  659. /**
  660. * 获取模型关联关系的表单数据.
  661. *
  662. * @param EloquentModel $model
  663. * @param array $inputs
  664. *
  665. * @return array
  666. */
  667. protected function getRelationInputs($model, $inputs = [])
  668. {
  669. $map = [];
  670. $relations = [];
  671. foreach ($inputs as $column => $value) {
  672. $relationColumn = null;
  673. if (method_exists($model, $column)) {
  674. $relationColumn = $column;
  675. } elseif (method_exists($model, $camelColumn = Str::camel($column))) {
  676. $relationColumn = $camelColumn;
  677. }
  678. if (! $relationColumn) {
  679. continue;
  680. }
  681. $relation = call_user_func([$model, $relationColumn]);
  682. if ($relation instanceof Relations\Relation) {
  683. $relations[$column] = $value;
  684. $map[$column] = $relationColumn;
  685. }
  686. }
  687. return [&$relations, $map];
  688. }
  689. /**
  690. * 更新关联关系数据.
  691. *
  692. * @param Form $form
  693. * @param EloquentModel $model
  694. * @param array $relationsData
  695. * @param array $relationKeyMap
  696. *
  697. * @throws \Exception
  698. */
  699. protected function updateRelation(Form $form, EloquentModel $model, array $relationsData, array $relationKeyMap)
  700. {
  701. foreach ($relationsData as $name => $values) {
  702. $relationName = $relationKeyMap[$name] ?? $name;
  703. if (! method_exists($model, $relationName)) {
  704. continue;
  705. }
  706. $relation = $model->$relationName();
  707. $oneToOneRelation = $relation instanceof Relations\HasOne
  708. || $relation instanceof Relations\MorphOne
  709. || $relation instanceof Relations\BelongsTo;
  710. $prepared = $oneToOneRelation ? $form->prepareUpdate([$name => $values]) : [$name => $values];
  711. if (empty($prepared)) {
  712. continue;
  713. }
  714. switch (true) {
  715. case $relation instanceof Relations\BelongsToMany:
  716. case $relation instanceof Relations\MorphToMany:
  717. if (isset($prepared[$name])) {
  718. $relation->sync($prepared[$name]);
  719. }
  720. break;
  721. case $relation instanceof Relations\HasOne:
  722. $related = $model->$relationName;
  723. // if related is empty
  724. if (is_null($related)) {
  725. $related = $relation->getRelated();
  726. $qualifiedParentKeyName = $relation->getQualifiedParentKeyName();
  727. $localKey = Arr::last(explode('.', $qualifiedParentKeyName));
  728. $related->{$relation->getForeignKeyName()} = $model->{$localKey};
  729. }
  730. foreach ($prepared[$name] as $column => $value) {
  731. $related->setAttribute($column, $value);
  732. }
  733. $related->save();
  734. break;
  735. case $relation instanceof Relations\BelongsTo:
  736. case $relation instanceof Relations\MorphTo:
  737. $parent = $model->$relationName;
  738. // if related is empty
  739. if (is_null($parent)) {
  740. $parent = $relation->getRelated();
  741. }
  742. foreach ($prepared[$name] as $column => $value) {
  743. $parent->setAttribute($column, $value);
  744. }
  745. $parent->save();
  746. // When in creating, associate two models
  747. $foreignKeyMethod = version_compare(app()->version(), '5.8.0', '<') ? 'getForeignKey' : 'getForeignKeyName';
  748. if (! $model->{$relation->{$foreignKeyMethod}()}) {
  749. $model->{$relation->{$foreignKeyMethod}()} = $parent->getKey();
  750. $model->save();
  751. }
  752. break;
  753. case $relation instanceof Relations\MorphOne:
  754. $related = $model->$relationName;
  755. if (is_null($related)) {
  756. $related = $relation->make();
  757. }
  758. foreach ($prepared[$name] as $column => $value) {
  759. $related->setAttribute($column, $value);
  760. }
  761. $related->save();
  762. break;
  763. case $relation instanceof Relations\HasMany:
  764. case $relation instanceof Relations\MorphMany:
  765. foreach ($prepared[$name] as $related) {
  766. /** @var Relations\Relation $relation */
  767. $relation = $model->$relationName();
  768. $keyName = $relation->getRelated()->getKeyName();
  769. $instance = $relation->findOrNew(Arr::get($related, $keyName));
  770. if (Arr::get($related, Form::REMOVE_FLAG_NAME) == 1) {
  771. $instance->delete();
  772. continue;
  773. }
  774. Arr::forget($related, Form::REMOVE_FLAG_NAME);
  775. $key = Arr::get($related, $relation->getModel()->getKeyName());
  776. if ($key === null || $key === '') {
  777. Arr::forget($related, $relation->getModel()->getKeyName());
  778. }
  779. $instance->fill($related);
  780. $instance->save();
  781. }
  782. break;
  783. }
  784. }
  785. }
  786. }