EloquentRepository.php 23 KB

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