Model.php 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653
  1. <?php
  2. namespace Illuminate\Database\Eloquent;
  3. use Exception;
  4. use ArrayAccess;
  5. use JsonSerializable;
  6. use Illuminate\Support\Arr;
  7. use Illuminate\Support\Str;
  8. use Illuminate\Contracts\Support\Jsonable;
  9. use Illuminate\Contracts\Support\Arrayable;
  10. use Illuminate\Support\Traits\ForwardsCalls;
  11. use Illuminate\Contracts\Routing\UrlRoutable;
  12. use Illuminate\Contracts\Queue\QueueableEntity;
  13. use Illuminate\Database\Eloquent\Relations\Pivot;
  14. use Illuminate\Contracts\Queue\QueueableCollection;
  15. use Illuminate\Support\Collection as BaseCollection;
  16. use Illuminate\Database\ConnectionResolverInterface as Resolver;
  17. abstract class Model implements ArrayAccess, Arrayable, Jsonable, JsonSerializable, QueueableEntity, UrlRoutable
  18. {
  19. use Concerns\HasAttributes,
  20. Concerns\HasEvents,
  21. Concerns\HasGlobalScopes,
  22. Concerns\HasRelationships,
  23. Concerns\HasTimestamps,
  24. Concerns\HidesAttributes,
  25. Concerns\GuardsAttributes,
  26. ForwardsCalls;
  27. /**
  28. * The connection name for the model.
  29. *
  30. * @var string|null
  31. */
  32. protected $connection;
  33. /**
  34. * The table associated with the model.
  35. *
  36. * @var string
  37. */
  38. protected $table;
  39. /**
  40. * The primary key for the model.
  41. *
  42. * @var string
  43. */
  44. protected $primaryKey = 'id';
  45. /**
  46. * The "type" of the primary key ID.
  47. *
  48. * @var string
  49. */
  50. protected $keyType = 'int';
  51. /**
  52. * Indicates if the IDs are auto-incrementing.
  53. *
  54. * @var bool
  55. */
  56. public $incrementing = true;
  57. /**
  58. * The relations to eager load on every query.
  59. *
  60. * @var array
  61. */
  62. protected $with = [];
  63. /**
  64. * The relationship counts that should be eager loaded on every query.
  65. *
  66. * @var array
  67. */
  68. protected $withCount = [];
  69. /**
  70. * The number of models to return for pagination.
  71. *
  72. * @var int
  73. */
  74. protected $perPage = 15;
  75. /**
  76. * Indicates if the model exists.
  77. *
  78. * @var bool
  79. */
  80. public $exists = false;
  81. /**
  82. * Indicates if the model was inserted during the current request lifecycle.
  83. *
  84. * @var bool
  85. */
  86. public $wasRecentlyCreated = false;
  87. /**
  88. * The connection resolver instance.
  89. *
  90. * @var \Illuminate\Database\ConnectionResolverInterface
  91. */
  92. protected static $resolver;
  93. /**
  94. * The event dispatcher instance.
  95. *
  96. * @var \Illuminate\Contracts\Events\Dispatcher
  97. */
  98. protected static $dispatcher;
  99. /**
  100. * The array of booted models.
  101. *
  102. * @var array
  103. */
  104. protected static $booted = [];
  105. /**
  106. * The array of trait initializers that will be called on each new instance.
  107. *
  108. * @var array
  109. */
  110. protected static $traitInitializers = [];
  111. /**
  112. * The array of global scopes on the model.
  113. *
  114. * @var array
  115. */
  116. protected static $globalScopes = [];
  117. /**
  118. * The list of models classes that should not be affected with touch.
  119. *
  120. * @var array
  121. */
  122. protected static $ignoreOnTouch = [];
  123. /**
  124. * The name of the "created at" column.
  125. *
  126. * @var string
  127. */
  128. const CREATED_AT = 'created_at';
  129. /**
  130. * The name of the "updated at" column.
  131. *
  132. * @var string
  133. */
  134. const UPDATED_AT = 'updated_at';
  135. /**
  136. * Create a new Eloquent model instance.
  137. *
  138. * @param array $attributes
  139. * @return void
  140. */
  141. public function __construct(array $attributes = [])
  142. {
  143. $this->bootIfNotBooted();
  144. $this->initializeTraits();
  145. $this->syncOriginal();
  146. $this->fill($attributes);
  147. }
  148. /**
  149. * Check if the model needs to be booted and if so, do it.
  150. *
  151. * @return void
  152. */
  153. protected function bootIfNotBooted()
  154. {
  155. if (! isset(static::$booted[static::class])) {
  156. static::$booted[static::class] = true;
  157. $this->fireModelEvent('booting', false);
  158. static::boot();
  159. $this->fireModelEvent('booted', false);
  160. }
  161. }
  162. /**
  163. * The "booting" method of the model.
  164. *
  165. * @return void
  166. */
  167. protected static function boot()
  168. {
  169. static::bootTraits();
  170. }
  171. /**
  172. * Boot all of the bootable traits on the model.
  173. *
  174. * @return void
  175. */
  176. protected static function bootTraits()
  177. {
  178. $class = static::class;
  179. $booted = [];
  180. static::$traitInitializers[$class] = [];
  181. foreach (class_uses_recursive($class) as $trait) {
  182. $method = 'boot'.class_basename($trait);
  183. if (method_exists($class, $method) && ! in_array($method, $booted)) {
  184. forward_static_call([$class, $method]);
  185. $booted[] = $method;
  186. }
  187. if (method_exists($class, $method = 'initialize'.class_basename($trait))) {
  188. static::$traitInitializers[$class][] = $method;
  189. static::$traitInitializers[$class] = array_unique(
  190. static::$traitInitializers[$class]
  191. );
  192. }
  193. }
  194. }
  195. /**
  196. * Initialize any initializable traits on the model.
  197. *
  198. * @return void
  199. */
  200. protected function initializeTraits()
  201. {
  202. foreach (static::$traitInitializers[static::class] as $method) {
  203. $this->{$method}();
  204. }
  205. }
  206. /**
  207. * Clear the list of booted models so they will be re-booted.
  208. *
  209. * @return void
  210. */
  211. public static function clearBootedModels()
  212. {
  213. static::$booted = [];
  214. static::$globalScopes = [];
  215. }
  216. /**
  217. * Disables relationship model touching for the current class during given callback scope.
  218. *
  219. * @param callable $callback
  220. * @return void
  221. */
  222. public static function withoutTouching(callable $callback)
  223. {
  224. static::withoutTouchingOn([static::class], $callback);
  225. }
  226. /**
  227. * Disables relationship model touching for the given model classes during given callback scope.
  228. *
  229. * @param array $models
  230. * @param callable $callback
  231. * @return void
  232. */
  233. public static function withoutTouchingOn(array $models, callable $callback)
  234. {
  235. static::$ignoreOnTouch = array_values(array_merge(static::$ignoreOnTouch, $models));
  236. try {
  237. call_user_func($callback);
  238. } finally {
  239. static::$ignoreOnTouch = array_values(array_diff(static::$ignoreOnTouch, $models));
  240. }
  241. }
  242. /**
  243. * Determine if the given model is ignoring touches.
  244. *
  245. * @param string|null $class
  246. * @return bool
  247. */
  248. public static function isIgnoringTouch($class = null)
  249. {
  250. $class = $class ?: static::class;
  251. if (! get_class_vars($class)['timestamps'] || ! $class::UPDATED_AT) {
  252. return true;
  253. }
  254. foreach (static::$ignoreOnTouch as $ignoredClass) {
  255. if ($class === $ignoredClass || is_subclass_of($class, $ignoredClass)) {
  256. return true;
  257. }
  258. }
  259. return false;
  260. }
  261. /**
  262. * Fill the model with an array of attributes.
  263. *
  264. * @param array $attributes
  265. * @return $this
  266. *
  267. * @throws \Illuminate\Database\Eloquent\MassAssignmentException
  268. */
  269. public function fill(array $attributes)
  270. {
  271. $totallyGuarded = $this->totallyGuarded();
  272. foreach ($this->fillableFromArray($attributes) as $key => $value) {
  273. $key = $this->removeTableFromKey($key);
  274. // The developers may choose to place some attributes in the "fillable" array
  275. // which means only those attributes may be set through mass assignment to
  276. // the model, and all others will just get ignored for security reasons.
  277. if ($this->isFillable($key)) {
  278. $this->setAttribute($key, $value);
  279. } elseif ($totallyGuarded) {
  280. throw new MassAssignmentException(sprintf(
  281. 'Add [%s] to fillable property to allow mass assignment on [%s].',
  282. $key, get_class($this)
  283. ));
  284. }
  285. }
  286. return $this;
  287. }
  288. /**
  289. * Fill the model with an array of attributes. Force mass assignment.
  290. *
  291. * @param array $attributes
  292. * @return $this
  293. */
  294. public function forceFill(array $attributes)
  295. {
  296. return static::unguarded(function () use ($attributes) {
  297. return $this->fill($attributes);
  298. });
  299. }
  300. /**
  301. * Qualify the given column name by the model's table.
  302. *
  303. * @param string $column
  304. * @return string
  305. */
  306. public function qualifyColumn($column)
  307. {
  308. if (Str::contains($column, '.')) {
  309. return $column;
  310. }
  311. return $this->getTable().'.'.$column;
  312. }
  313. /**
  314. * Remove the table name from a given key.
  315. *
  316. * @param string $key
  317. * @return string
  318. */
  319. protected function removeTableFromKey($key)
  320. {
  321. return Str::contains($key, '.') ? last(explode('.', $key)) : $key;
  322. }
  323. /**
  324. * Create a new instance of the given model.
  325. *
  326. * @param array $attributes
  327. * @param bool $exists
  328. * @return static
  329. */
  330. public function newInstance($attributes = [], $exists = false)
  331. {
  332. // This method just provides a convenient way for us to generate fresh model
  333. // instances of this current model. It is particularly useful during the
  334. // hydration of new objects via the Eloquent query builder instances.
  335. $model = new static((array) $attributes);
  336. $model->exists = $exists;
  337. $model->setConnection(
  338. $this->getConnectionName()
  339. );
  340. $model->setTable($this->getTable());
  341. return $model;
  342. }
  343. /**
  344. * Create a new model instance that is existing.
  345. *
  346. * @param array $attributes
  347. * @param string|null $connection
  348. * @return static
  349. */
  350. public function newFromBuilder($attributes = [], $connection = null)
  351. {
  352. $model = $this->newInstance([], true);
  353. $model->setRawAttributes((array) $attributes, true);
  354. $model->setConnection($connection ?: $this->getConnectionName());
  355. $model->fireModelEvent('retrieved', false);
  356. return $model;
  357. }
  358. /**
  359. * Begin querying the model on a given connection.
  360. *
  361. * @param string|null $connection
  362. * @return \Illuminate\Database\Eloquent\Builder
  363. */
  364. public static function on($connection = null)
  365. {
  366. // First we will just create a fresh instance of this model, and then we can set the
  367. // connection on the model so that it is used for the queries we execute, as well
  368. // as being set on every relation we retrieve without a custom connection name.
  369. $instance = new static;
  370. $instance->setConnection($connection);
  371. return $instance->newQuery();
  372. }
  373. /**
  374. * Begin querying the model on the write connection.
  375. *
  376. * @return \Illuminate\Database\Query\Builder
  377. */
  378. public static function onWriteConnection()
  379. {
  380. return static::query()->useWritePdo();
  381. }
  382. /**
  383. * Get all of the models from the database.
  384. *
  385. * @param array|mixed $columns
  386. * @return \Illuminate\Database\Eloquent\Collection|static[]
  387. */
  388. public static function all($columns = ['*'])
  389. {
  390. return static::query()->get(
  391. is_array($columns) ? $columns : func_get_args()
  392. );
  393. }
  394. /**
  395. * Begin querying a model with eager loading.
  396. *
  397. * @param array|string $relations
  398. * @return \Illuminate\Database\Eloquent\Builder|static
  399. */
  400. public static function with($relations)
  401. {
  402. return static::query()->with(
  403. is_string($relations) ? func_get_args() : $relations
  404. );
  405. }
  406. /**
  407. * Eager load relations on the model.
  408. *
  409. * @param array|string $relations
  410. * @return $this
  411. */
  412. public function load($relations)
  413. {
  414. $query = $this->newQueryWithoutRelationships()->with(
  415. is_string($relations) ? func_get_args() : $relations
  416. );
  417. $query->eagerLoadRelations([$this]);
  418. return $this;
  419. }
  420. /**
  421. * Eager load relations on the model if they are not already eager loaded.
  422. *
  423. * @param array|string $relations
  424. * @return $this
  425. */
  426. public function loadMissing($relations)
  427. {
  428. $relations = is_string($relations) ? func_get_args() : $relations;
  429. $this->newCollection([$this])->loadMissing($relations);
  430. return $this;
  431. }
  432. /**
  433. * Eager load relation counts on the model.
  434. *
  435. * @param array|string $relations
  436. * @return $this
  437. */
  438. public function loadCount($relations)
  439. {
  440. $relations = is_string($relations) ? func_get_args() : $relations;
  441. $this->newCollection([$this])->loadCount($relations);
  442. return $this;
  443. }
  444. /**
  445. * Increment a column's value by a given amount.
  446. *
  447. * @param string $column
  448. * @param float|int $amount
  449. * @param array $extra
  450. * @return int
  451. */
  452. protected function increment($column, $amount = 1, array $extra = [])
  453. {
  454. return $this->incrementOrDecrement($column, $amount, $extra, 'increment');
  455. }
  456. /**
  457. * Decrement a column's value by a given amount.
  458. *
  459. * @param string $column
  460. * @param float|int $amount
  461. * @param array $extra
  462. * @return int
  463. */
  464. protected function decrement($column, $amount = 1, array $extra = [])
  465. {
  466. return $this->incrementOrDecrement($column, $amount, $extra, 'decrement');
  467. }
  468. /**
  469. * Run the increment or decrement method on the model.
  470. *
  471. * @param string $column
  472. * @param float|int $amount
  473. * @param array $extra
  474. * @param string $method
  475. * @return int
  476. */
  477. protected function incrementOrDecrement($column, $amount, $extra, $method)
  478. {
  479. $query = $this->newQueryWithoutRelationships();
  480. if (! $this->exists) {
  481. return $query->{$method}($column, $amount, $extra);
  482. }
  483. $this->incrementOrDecrementAttributeValue($column, $amount, $extra, $method);
  484. return $query->where(
  485. $this->getKeyName(), $this->getKey()
  486. )->{$method}($column, $amount, $extra);
  487. }
  488. /**
  489. * Increment the underlying attribute value and sync with original.
  490. *
  491. * @param string $column
  492. * @param float|int $amount
  493. * @param array $extra
  494. * @param string $method
  495. * @return void
  496. */
  497. protected function incrementOrDecrementAttributeValue($column, $amount, $extra, $method)
  498. {
  499. $this->{$column} = $this->{$column} + ($method === 'increment' ? $amount : $amount * -1);
  500. $this->forceFill($extra);
  501. $this->syncOriginalAttribute($column);
  502. }
  503. /**
  504. * Update the model in the database.
  505. *
  506. * @param array $attributes
  507. * @param array $options
  508. * @return bool
  509. */
  510. public function update(array $attributes = [], array $options = [])
  511. {
  512. if (! $this->exists) {
  513. return false;
  514. }
  515. return $this->fill($attributes)->save($options);
  516. }
  517. /**
  518. * Save the model and all of its relationships.
  519. *
  520. * @return bool
  521. */
  522. public function push()
  523. {
  524. if (! $this->save()) {
  525. return false;
  526. }
  527. // To sync all of the relationships to the database, we will simply spin through
  528. // the relationships and save each model via this "push" method, which allows
  529. // us to recurse into all of these nested relations for the model instance.
  530. foreach ($this->relations as $models) {
  531. $models = $models instanceof Collection
  532. ? $models->all() : [$models];
  533. foreach (array_filter($models) as $model) {
  534. if (! $model->push()) {
  535. return false;
  536. }
  537. }
  538. }
  539. return true;
  540. }
  541. /**
  542. * Save the model to the database.
  543. *
  544. * @param array $options
  545. * @return bool
  546. */
  547. public function save(array $options = [])
  548. {
  549. $query = $this->newModelQuery();
  550. // If the "saving" event returns false we'll bail out of the save and return
  551. // false, indicating that the save failed. This provides a chance for any
  552. // listeners to cancel save operations if validations fail or whatever.
  553. if ($this->fireModelEvent('saving') === false) {
  554. return false;
  555. }
  556. // If the model already exists in the database we can just update our record
  557. // that is already in this database using the current IDs in this "where"
  558. // clause to only update this model. Otherwise, we'll just insert them.
  559. if ($this->exists) {
  560. $saved = $this->isDirty() ?
  561. $this->performUpdate($query) : true;
  562. }
  563. // If the model is brand new, we'll insert it into our database and set the
  564. // ID attribute on the model to the value of the newly inserted row's ID
  565. // which is typically an auto-increment value managed by the database.
  566. else {
  567. $saved = $this->performInsert($query);
  568. if (! $this->getConnectionName() &&
  569. $connection = $query->getConnection()) {
  570. $this->setConnection($connection->getName());
  571. }
  572. }
  573. // If the model is successfully saved, we need to do a few more things once
  574. // that is done. We will call the "saved" method here to run any actions
  575. // we need to happen after a model gets successfully saved right here.
  576. if ($saved) {
  577. $this->finishSave($options);
  578. }
  579. return $saved;
  580. }
  581. /**
  582. * Save the model to the database using transaction.
  583. *
  584. * @param array $options
  585. * @return bool
  586. *
  587. * @throws \Throwable
  588. */
  589. public function saveOrFail(array $options = [])
  590. {
  591. return $this->getConnection()->transaction(function () use ($options) {
  592. return $this->save($options);
  593. });
  594. }
  595. /**
  596. * Perform any actions that are necessary after the model is saved.
  597. *
  598. * @param array $options
  599. * @return void
  600. */
  601. protected function finishSave(array $options)
  602. {
  603. $this->fireModelEvent('saved', false);
  604. if ($this->isDirty() && ($options['touch'] ?? true)) {
  605. $this->touchOwners();
  606. }
  607. $this->syncOriginal();
  608. }
  609. /**
  610. * Perform a model update operation.
  611. *
  612. * @param \Illuminate\Database\Eloquent\Builder $query
  613. * @return bool
  614. */
  615. protected function performUpdate(Builder $query)
  616. {
  617. // If the updating event returns false, we will cancel the update operation so
  618. // developers can hook Validation systems into their models and cancel this
  619. // operation if the model does not pass validation. Otherwise, we update.
  620. if ($this->fireModelEvent('updating') === false) {
  621. return false;
  622. }
  623. // First we need to create a fresh query instance and touch the creation and
  624. // update timestamp on the model which are maintained by us for developer
  625. // convenience. Then we will just continue saving the model instances.
  626. if ($this->usesTimestamps()) {
  627. $this->updateTimestamps();
  628. }
  629. // Once we have run the update operation, we will fire the "updated" event for
  630. // this model instance. This will allow developers to hook into these after
  631. // models are updated, giving them a chance to do any special processing.
  632. $dirty = $this->getDirty();
  633. if (count($dirty) > 0) {
  634. $this->setKeysForSaveQuery($query)->update($dirty);
  635. $this->syncChanges();
  636. $this->fireModelEvent('updated', false);
  637. }
  638. return true;
  639. }
  640. /**
  641. * Set the keys for a save update query.
  642. *
  643. * @param \Illuminate\Database\Eloquent\Builder $query
  644. * @return \Illuminate\Database\Eloquent\Builder
  645. */
  646. protected function setKeysForSaveQuery(Builder $query)
  647. {
  648. $query->where($this->getKeyName(), '=', $this->getKeyForSaveQuery());
  649. return $query;
  650. }
  651. /**
  652. * Get the primary key value for a save query.
  653. *
  654. * @return mixed
  655. */
  656. protected function getKeyForSaveQuery()
  657. {
  658. return $this->original[$this->getKeyName()]
  659. ?? $this->getKey();
  660. }
  661. /**
  662. * Perform a model insert operation.
  663. *
  664. * @param \Illuminate\Database\Eloquent\Builder $query
  665. * @return bool
  666. */
  667. protected function performInsert(Builder $query)
  668. {
  669. if ($this->fireModelEvent('creating') === false) {
  670. return false;
  671. }
  672. // First we'll need to create a fresh query instance and touch the creation and
  673. // update timestamps on this model, which are maintained by us for developer
  674. // convenience. After, we will just continue saving these model instances.
  675. if ($this->usesTimestamps()) {
  676. $this->updateTimestamps();
  677. }
  678. // If the model has an incrementing key, we can use the "insertGetId" method on
  679. // the query builder, which will give us back the final inserted ID for this
  680. // table from the database. Not all tables have to be incrementing though.
  681. $attributes = $this->getAttributes();
  682. if ($this->getIncrementing()) {
  683. $this->insertAndSetId($query, $attributes);
  684. }
  685. // If the table isn't incrementing we'll simply insert these attributes as they
  686. // are. These attribute arrays must contain an "id" column previously placed
  687. // there by the developer as the manually determined key for these models.
  688. else {
  689. if (empty($attributes)) {
  690. return true;
  691. }
  692. $query->insert($attributes);
  693. }
  694. // We will go ahead and set the exists property to true, so that it is set when
  695. // the created event is fired, just in case the developer tries to update it
  696. // during the event. This will allow them to do so and run an update here.
  697. $this->exists = true;
  698. $this->wasRecentlyCreated = true;
  699. $this->fireModelEvent('created', false);
  700. return true;
  701. }
  702. /**
  703. * Insert the given attributes and set the ID on the model.
  704. *
  705. * @param \Illuminate\Database\Eloquent\Builder $query
  706. * @param array $attributes
  707. * @return void
  708. */
  709. protected function insertAndSetId(Builder $query, $attributes)
  710. {
  711. $id = $query->insertGetId($attributes, $keyName = $this->getKeyName());
  712. $this->setAttribute($keyName, $id);
  713. }
  714. /**
  715. * Destroy the models for the given IDs.
  716. *
  717. * @param \Illuminate\Support\Collection|array|int $ids
  718. * @return int
  719. */
  720. public static function destroy($ids)
  721. {
  722. // We'll initialize a count here so we will return the total number of deletes
  723. // for the operation. The developers can then check this number as a boolean
  724. // type value or get this total count of records deleted for logging, etc.
  725. $count = 0;
  726. if ($ids instanceof BaseCollection) {
  727. $ids = $ids->all();
  728. }
  729. $ids = is_array($ids) ? $ids : func_get_args();
  730. // We will actually pull the models from the database table and call delete on
  731. // each of them individually so that their events get fired properly with a
  732. // correct set of attributes in case the developers wants to check these.
  733. $key = ($instance = new static)->getKeyName();
  734. foreach ($instance->whereIn($key, $ids)->get() as $model) {
  735. if ($model->delete()) {
  736. $count++;
  737. }
  738. }
  739. return $count;
  740. }
  741. /**
  742. * Delete the model from the database.
  743. *
  744. * @return bool|null
  745. *
  746. * @throws \Exception
  747. */
  748. public function delete()
  749. {
  750. if (is_null($this->getKeyName())) {
  751. throw new Exception('No primary key defined on model.');
  752. }
  753. // If the model doesn't exist, there is nothing to delete so we'll just return
  754. // immediately and not do anything else. Otherwise, we will continue with a
  755. // deletion process on the model, firing the proper events, and so forth.
  756. if (! $this->exists) {
  757. return;
  758. }
  759. if ($this->fireModelEvent('deleting') === false) {
  760. return false;
  761. }
  762. // Here, we'll touch the owning models, verifying these timestamps get updated
  763. // for the models. This will allow any caching to get broken on the parents
  764. // by the timestamp. Then we will go ahead and delete the model instance.
  765. $this->touchOwners();
  766. $this->performDeleteOnModel();
  767. // Once the model has been deleted, we will fire off the deleted event so that
  768. // the developers may hook into post-delete operations. We will then return
  769. // a boolean true as the delete is presumably successful on the database.
  770. $this->fireModelEvent('deleted', false);
  771. return true;
  772. }
  773. /**
  774. * Force a hard delete on a soft deleted model.
  775. *
  776. * This method protects developers from running forceDelete when trait is missing.
  777. *
  778. * @return bool|null
  779. */
  780. public function forceDelete()
  781. {
  782. return $this->delete();
  783. }
  784. /**
  785. * Perform the actual delete query on this model instance.
  786. *
  787. * @return void
  788. */
  789. protected function performDeleteOnModel()
  790. {
  791. $this->setKeysForSaveQuery($this->newModelQuery())->delete();
  792. $this->exists = false;
  793. }
  794. /**
  795. * Begin querying the model.
  796. *
  797. * @return \Illuminate\Database\Eloquent\Builder
  798. */
  799. public static function query()
  800. {
  801. return (new static)->newQuery();
  802. }
  803. /**
  804. * Get a new query builder for the model's table.
  805. *
  806. * @return \Illuminate\Database\Eloquent\Builder
  807. */
  808. public function newQuery()
  809. {
  810. return $this->registerGlobalScopes($this->newQueryWithoutScopes());
  811. }
  812. /**
  813. * Get a new query builder that doesn't have any global scopes or eager loading.
  814. *
  815. * @return \Illuminate\Database\Eloquent\Builder|static
  816. */
  817. public function newModelQuery()
  818. {
  819. return $this->newEloquentBuilder(
  820. $this->newBaseQueryBuilder()
  821. )->setModel($this);
  822. }
  823. /**
  824. * Get a new query builder with no relationships loaded.
  825. *
  826. * @return \Illuminate\Database\Eloquent\Builder
  827. */
  828. public function newQueryWithoutRelationships()
  829. {
  830. return $this->registerGlobalScopes($this->newModelQuery());
  831. }
  832. /**
  833. * Register the global scopes for this builder instance.
  834. *
  835. * @param \Illuminate\Database\Eloquent\Builder $builder
  836. * @return \Illuminate\Database\Eloquent\Builder
  837. */
  838. public function registerGlobalScopes($builder)
  839. {
  840. foreach ($this->getGlobalScopes() as $identifier => $scope) {
  841. $builder->withGlobalScope($identifier, $scope);
  842. }
  843. return $builder;
  844. }
  845. /**
  846. * Get a new query builder that doesn't have any global scopes.
  847. *
  848. * @return \Illuminate\Database\Eloquent\Builder|static
  849. */
  850. public function newQueryWithoutScopes()
  851. {
  852. return $this->newModelQuery()
  853. ->with($this->with)
  854. ->withCount($this->withCount);
  855. }
  856. /**
  857. * Get a new query instance without a given scope.
  858. *
  859. * @param \Illuminate\Database\Eloquent\Scope|string $scope
  860. * @return \Illuminate\Database\Eloquent\Builder
  861. */
  862. public function newQueryWithoutScope($scope)
  863. {
  864. return $this->newQuery()->withoutGlobalScope($scope);
  865. }
  866. /**
  867. * Get a new query to restore one or more models by their queueable IDs.
  868. *
  869. * @param array|int $ids
  870. * @return \Illuminate\Database\Eloquent\Builder
  871. */
  872. public function newQueryForRestoration($ids)
  873. {
  874. return is_array($ids)
  875. ? $this->newQueryWithoutScopes()->whereIn($this->getQualifiedKeyName(), $ids)
  876. : $this->newQueryWithoutScopes()->whereKey($ids);
  877. }
  878. /**
  879. * Create a new Eloquent query builder for the model.
  880. *
  881. * @param \Illuminate\Database\Query\Builder $query
  882. * @return \Illuminate\Database\Eloquent\Builder|static
  883. */
  884. public function newEloquentBuilder($query)
  885. {
  886. return new Builder($query);
  887. }
  888. /**
  889. * Get a new query builder instance for the connection.
  890. *
  891. * @return \Illuminate\Database\Query\Builder
  892. */
  893. protected function newBaseQueryBuilder()
  894. {
  895. return $this->getConnection()->query();
  896. }
  897. /**
  898. * Create a new Eloquent Collection instance.
  899. *
  900. * @param array $models
  901. * @return \Illuminate\Database\Eloquent\Collection
  902. */
  903. public function newCollection(array $models = [])
  904. {
  905. return new Collection($models);
  906. }
  907. /**
  908. * Create a new pivot model instance.
  909. *
  910. * @param \Illuminate\Database\Eloquent\Model $parent
  911. * @param array $attributes
  912. * @param string $table
  913. * @param bool $exists
  914. * @param string|null $using
  915. * @return \Illuminate\Database\Eloquent\Relations\Pivot
  916. */
  917. public function newPivot(self $parent, array $attributes, $table, $exists, $using = null)
  918. {
  919. return $using ? $using::fromRawAttributes($parent, $attributes, $table, $exists)
  920. : Pivot::fromAttributes($parent, $attributes, $table, $exists);
  921. }
  922. /**
  923. * Convert the model instance to an array.
  924. *
  925. * @return array
  926. */
  927. public function toArray()
  928. {
  929. return array_merge($this->attributesToArray(), $this->relationsToArray());
  930. }
  931. /**
  932. * Convert the model instance to JSON.
  933. *
  934. * @param int $options
  935. * @return string
  936. *
  937. * @throws \Illuminate\Database\Eloquent\JsonEncodingException
  938. */
  939. public function toJson($options = 0)
  940. {
  941. $json = json_encode($this->jsonSerialize(), $options);
  942. if (JSON_ERROR_NONE !== json_last_error()) {
  943. throw JsonEncodingException::forModel($this, json_last_error_msg());
  944. }
  945. return $json;
  946. }
  947. /**
  948. * Convert the object into something JSON serializable.
  949. *
  950. * @return array
  951. */
  952. public function jsonSerialize()
  953. {
  954. return $this->toArray();
  955. }
  956. /**
  957. * Reload a fresh model instance from the database.
  958. *
  959. * @param array|string $with
  960. * @return static|null
  961. */
  962. public function fresh($with = [])
  963. {
  964. if (! $this->exists) {
  965. return;
  966. }
  967. return static::newQueryWithoutScopes()
  968. ->with(is_string($with) ? func_get_args() : $with)
  969. ->where($this->getKeyName(), $this->getKey())
  970. ->first();
  971. }
  972. /**
  973. * Reload the current model instance with fresh attributes from the database.
  974. *
  975. * @return $this
  976. */
  977. public function refresh()
  978. {
  979. if (! $this->exists) {
  980. return $this;
  981. }
  982. $this->setRawAttributes(
  983. static::newQueryWithoutScopes()->findOrFail($this->getKey())->attributes
  984. );
  985. $this->load(collect($this->relations)->except('pivot')->keys()->toArray());
  986. $this->syncOriginal();
  987. return $this;
  988. }
  989. /**
  990. * Clone the model into a new, non-existing instance.
  991. *
  992. * @param array|null $except
  993. * @return static
  994. */
  995. public function replicate(array $except = null)
  996. {
  997. $defaults = [
  998. $this->getKeyName(),
  999. $this->getCreatedAtColumn(),
  1000. $this->getUpdatedAtColumn(),
  1001. ];
  1002. $attributes = Arr::except(
  1003. $this->attributes, $except ? array_unique(array_merge($except, $defaults)) : $defaults
  1004. );
  1005. return tap(new static, function ($instance) use ($attributes) {
  1006. $instance->setRawAttributes($attributes);
  1007. $instance->setRelations($this->relations);
  1008. $instance->fireModelEvent('replicating', false);
  1009. });
  1010. }
  1011. /**
  1012. * Determine if two models have the same ID and belong to the same table.
  1013. *
  1014. * @param \Illuminate\Database\Eloquent\Model|null $model
  1015. * @return bool
  1016. */
  1017. public function is($model)
  1018. {
  1019. return ! is_null($model) &&
  1020. $this->getKey() === $model->getKey() &&
  1021. $this->getTable() === $model->getTable() &&
  1022. $this->getConnectionName() === $model->getConnectionName();
  1023. }
  1024. /**
  1025. * Determine if two models are not the same.
  1026. *
  1027. * @param \Illuminate\Database\Eloquent\Model|null $model
  1028. * @return bool
  1029. */
  1030. public function isNot($model)
  1031. {
  1032. return ! $this->is($model);
  1033. }
  1034. /**
  1035. * Get the database connection for the model.
  1036. *
  1037. * @return \Illuminate\Database\Connection
  1038. */
  1039. public function getConnection()
  1040. {
  1041. return static::resolveConnection($this->getConnectionName());
  1042. }
  1043. /**
  1044. * Get the current connection name for the model.
  1045. *
  1046. * @return string|null
  1047. */
  1048. public function getConnectionName()
  1049. {
  1050. return $this->connection;
  1051. }
  1052. /**
  1053. * Set the connection associated with the model.
  1054. *
  1055. * @param string|null $name
  1056. * @return $this
  1057. */
  1058. public function setConnection($name)
  1059. {
  1060. $this->connection = $name;
  1061. return $this;
  1062. }
  1063. /**
  1064. * Resolve a connection instance.
  1065. *
  1066. * @param string|null $connection
  1067. * @return \Illuminate\Database\Connection
  1068. */
  1069. public static function resolveConnection($connection = null)
  1070. {
  1071. return static::$resolver->connection($connection);
  1072. }
  1073. /**
  1074. * Get the connection resolver instance.
  1075. *
  1076. * @return \Illuminate\Database\ConnectionResolverInterface
  1077. */
  1078. public static function getConnectionResolver()
  1079. {
  1080. return static::$resolver;
  1081. }
  1082. /**
  1083. * Set the connection resolver instance.
  1084. *
  1085. * @param \Illuminate\Database\ConnectionResolverInterface $resolver
  1086. * @return void
  1087. */
  1088. public static function setConnectionResolver(Resolver $resolver)
  1089. {
  1090. static::$resolver = $resolver;
  1091. }
  1092. /**
  1093. * Unset the connection resolver for models.
  1094. *
  1095. * @return void
  1096. */
  1097. public static function unsetConnectionResolver()
  1098. {
  1099. static::$resolver = null;
  1100. }
  1101. /**
  1102. * Get the table associated with the model.
  1103. *
  1104. * @return string
  1105. */
  1106. public function getTable()
  1107. {
  1108. return $this->table ?? Str::snake(Str::pluralStudly(class_basename($this)));
  1109. }
  1110. /**
  1111. * Set the table associated with the model.
  1112. *
  1113. * @param string $table
  1114. * @return $this
  1115. */
  1116. public function setTable($table)
  1117. {
  1118. $this->table = $table;
  1119. return $this;
  1120. }
  1121. /**
  1122. * Get the primary key for the model.
  1123. *
  1124. * @return string
  1125. */
  1126. public function getKeyName()
  1127. {
  1128. return $this->primaryKey;
  1129. }
  1130. /**
  1131. * Set the primary key for the model.
  1132. *
  1133. * @param string $key
  1134. * @return $this
  1135. */
  1136. public function setKeyName($key)
  1137. {
  1138. $this->primaryKey = $key;
  1139. return $this;
  1140. }
  1141. /**
  1142. * Get the table qualified key name.
  1143. *
  1144. * @return string
  1145. */
  1146. public function getQualifiedKeyName()
  1147. {
  1148. return $this->qualifyColumn($this->getKeyName());
  1149. }
  1150. /**
  1151. * Get the auto-incrementing key type.
  1152. *
  1153. * @return string
  1154. */
  1155. public function getKeyType()
  1156. {
  1157. return $this->keyType;
  1158. }
  1159. /**
  1160. * Set the data type for the primary key.
  1161. *
  1162. * @param string $type
  1163. * @return $this
  1164. */
  1165. public function setKeyType($type)
  1166. {
  1167. $this->keyType = $type;
  1168. return $this;
  1169. }
  1170. /**
  1171. * Get the value indicating whether the IDs are incrementing.
  1172. *
  1173. * @return bool
  1174. */
  1175. public function getIncrementing()
  1176. {
  1177. return $this->incrementing;
  1178. }
  1179. /**
  1180. * Set whether IDs are incrementing.
  1181. *
  1182. * @param bool $value
  1183. * @return $this
  1184. */
  1185. public function setIncrementing($value)
  1186. {
  1187. $this->incrementing = $value;
  1188. return $this;
  1189. }
  1190. /**
  1191. * Get the value of the model's primary key.
  1192. *
  1193. * @return mixed
  1194. */
  1195. public function getKey()
  1196. {
  1197. return $this->getAttribute($this->getKeyName());
  1198. }
  1199. /**
  1200. * Get the queueable identity for the entity.
  1201. *
  1202. * @return mixed
  1203. */
  1204. public function getQueueableId()
  1205. {
  1206. return $this->getKey();
  1207. }
  1208. /**
  1209. * Get the queueable relationships for the entity.
  1210. *
  1211. * @return array
  1212. */
  1213. public function getQueueableRelations()
  1214. {
  1215. $relations = [];
  1216. foreach ($this->getRelations() as $key => $relation) {
  1217. if (! method_exists($this, $key)) {
  1218. continue;
  1219. }
  1220. $relations[] = $key;
  1221. if ($relation instanceof QueueableCollection) {
  1222. foreach ($relation->getQueueableRelations() as $collectionValue) {
  1223. $relations[] = $key.'.'.$collectionValue;
  1224. }
  1225. }
  1226. if ($relation instanceof QueueableEntity) {
  1227. foreach ($relation->getQueueableRelations() as $entityKey => $entityValue) {
  1228. $relations[] = $key.'.'.$entityValue;
  1229. }
  1230. }
  1231. }
  1232. return array_unique($relations);
  1233. }
  1234. /**
  1235. * Get the queueable connection for the entity.
  1236. *
  1237. * @return string|null
  1238. */
  1239. public function getQueueableConnection()
  1240. {
  1241. return $this->getConnectionName();
  1242. }
  1243. /**
  1244. * Get the value of the model's route key.
  1245. *
  1246. * @return mixed
  1247. */
  1248. public function getRouteKey()
  1249. {
  1250. return $this->getAttribute($this->getRouteKeyName());
  1251. }
  1252. /**
  1253. * Get the route key for the model.
  1254. *
  1255. * @return string
  1256. */
  1257. public function getRouteKeyName()
  1258. {
  1259. return $this->getKeyName();
  1260. }
  1261. /**
  1262. * Retrieve the model for a bound value.
  1263. *
  1264. * @param mixed $value
  1265. * @return \Illuminate\Database\Eloquent\Model|null
  1266. */
  1267. public function resolveRouteBinding($value)
  1268. {
  1269. return $this->where($this->getRouteKeyName(), $value)->first();
  1270. }
  1271. /**
  1272. * Get the default foreign key name for the model.
  1273. *
  1274. * @return string
  1275. */
  1276. public function getForeignKey()
  1277. {
  1278. return Str::snake(class_basename($this)).'_'.$this->getKeyName();
  1279. }
  1280. /**
  1281. * Get the number of models to return per page.
  1282. *
  1283. * @return int
  1284. */
  1285. public function getPerPage()
  1286. {
  1287. return $this->perPage;
  1288. }
  1289. /**
  1290. * Set the number of models to return per page.
  1291. *
  1292. * @param int $perPage
  1293. * @return $this
  1294. */
  1295. public function setPerPage($perPage)
  1296. {
  1297. $this->perPage = $perPage;
  1298. return $this;
  1299. }
  1300. /**
  1301. * Dynamically retrieve attributes on the model.
  1302. *
  1303. * @param string $key
  1304. * @return mixed
  1305. */
  1306. public function __get($key)
  1307. {
  1308. return $this->getAttribute($key);
  1309. }
  1310. /**
  1311. * Dynamically set attributes on the model.
  1312. *
  1313. * @param string $key
  1314. * @param mixed $value
  1315. * @return void
  1316. */
  1317. public function __set($key, $value)
  1318. {
  1319. $this->setAttribute($key, $value);
  1320. }
  1321. /**
  1322. * Determine if the given attribute exists.
  1323. *
  1324. * @param mixed $offset
  1325. * @return bool
  1326. */
  1327. public function offsetExists($offset)
  1328. {
  1329. return ! is_null($this->getAttribute($offset));
  1330. }
  1331. /**
  1332. * Get the value for a given offset.
  1333. *
  1334. * @param mixed $offset
  1335. * @return mixed
  1336. */
  1337. public function offsetGet($offset)
  1338. {
  1339. return $this->getAttribute($offset);
  1340. }
  1341. /**
  1342. * Set the value for a given offset.
  1343. *
  1344. * @param mixed $offset
  1345. * @param mixed $value
  1346. * @return void
  1347. */
  1348. public function offsetSet($offset, $value)
  1349. {
  1350. $this->setAttribute($offset, $value);
  1351. }
  1352. /**
  1353. * Unset the value for a given offset.
  1354. *
  1355. * @param mixed $offset
  1356. * @return void
  1357. */
  1358. public function offsetUnset($offset)
  1359. {
  1360. unset($this->attributes[$offset], $this->relations[$offset]);
  1361. }
  1362. /**
  1363. * Determine if an attribute or relation exists on the model.
  1364. *
  1365. * @param string $key
  1366. * @return bool
  1367. */
  1368. public function __isset($key)
  1369. {
  1370. return $this->offsetExists($key);
  1371. }
  1372. /**
  1373. * Unset an attribute on the model.
  1374. *
  1375. * @param string $key
  1376. * @return void
  1377. */
  1378. public function __unset($key)
  1379. {
  1380. $this->offsetUnset($key);
  1381. }
  1382. /**
  1383. * Handle dynamic method calls into the model.
  1384. *
  1385. * @param string $method
  1386. * @param array $parameters
  1387. * @return mixed
  1388. */
  1389. public function __call($method, $parameters)
  1390. {
  1391. if (in_array($method, ['increment', 'decrement'])) {
  1392. return $this->$method(...$parameters);
  1393. }
  1394. return $this->forwardCallTo($this->newQuery(), $method, $parameters);
  1395. }
  1396. /**
  1397. * Handle dynamic static method calls into the method.
  1398. *
  1399. * @param string $method
  1400. * @param array $parameters
  1401. * @return mixed
  1402. */
  1403. public static function __callStatic($method, $parameters)
  1404. {
  1405. return (new static)->$method(...$parameters);
  1406. }
  1407. /**
  1408. * Convert the model to its string representation.
  1409. *
  1410. * @return string
  1411. */
  1412. public function __toString()
  1413. {
  1414. return $this->toJson();
  1415. }
  1416. /**
  1417. * When a model is being unserialized, check if it needs to be booted.
  1418. *
  1419. * @return void
  1420. */
  1421. public function __wakeup()
  1422. {
  1423. $this->bootIfNotBooted();
  1424. }
  1425. }