Factory.php 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934
  1. <?php
  2. namespace Illuminate\Database\Eloquent\Factories;
  3. use Closure;
  4. use Faker\Generator;
  5. use Illuminate\Container\Container;
  6. use Illuminate\Contracts\Foundation\Application;
  7. use Illuminate\Database\Eloquent\Collection as EloquentCollection;
  8. use Illuminate\Database\Eloquent\Model;
  9. use Illuminate\Database\Eloquent\SoftDeletes;
  10. use Illuminate\Support\Carbon;
  11. use Illuminate\Support\Collection;
  12. use Illuminate\Support\Enumerable;
  13. use Illuminate\Support\Str;
  14. use Illuminate\Support\Traits\Conditionable;
  15. use Illuminate\Support\Traits\ForwardsCalls;
  16. use Illuminate\Support\Traits\Macroable;
  17. use Throwable;
  18. /**
  19. * @template TModel of \Illuminate\Database\Eloquent\Model
  20. *
  21. * @method $this trashed()
  22. */
  23. abstract class Factory
  24. {
  25. use Conditionable, ForwardsCalls, Macroable {
  26. __call as macroCall;
  27. }
  28. /**
  29. * The name of the factory's corresponding model.
  30. *
  31. * @var class-string<\Illuminate\Database\Eloquent\Model|TModel>
  32. */
  33. protected $model;
  34. /**
  35. * The number of models that should be generated.
  36. *
  37. * @var int|null
  38. */
  39. protected $count;
  40. /**
  41. * The state transformations that will be applied to the model.
  42. *
  43. * @var \Illuminate\Support\Collection
  44. */
  45. protected $states;
  46. /**
  47. * The parent relationships that will be applied to the model.
  48. *
  49. * @var \Illuminate\Support\Collection
  50. */
  51. protected $has;
  52. /**
  53. * The child relationships that will be applied to the model.
  54. *
  55. * @var \Illuminate\Support\Collection
  56. */
  57. protected $for;
  58. /**
  59. * The model instances to always use when creating relationships.
  60. *
  61. * @var \Illuminate\Support\Collection
  62. */
  63. protected $recycle;
  64. /**
  65. * The "after making" callbacks that will be applied to the model.
  66. *
  67. * @var \Illuminate\Support\Collection
  68. */
  69. protected $afterMaking;
  70. /**
  71. * The "after creating" callbacks that will be applied to the model.
  72. *
  73. * @var \Illuminate\Support\Collection
  74. */
  75. protected $afterCreating;
  76. /**
  77. * The name of the database connection that will be used to create the models.
  78. *
  79. * @var string|null
  80. */
  81. protected $connection;
  82. /**
  83. * The current Faker instance.
  84. *
  85. * @var \Faker\Generator
  86. */
  87. protected $faker;
  88. /**
  89. * The default namespace where factories reside.
  90. *
  91. * @var string
  92. */
  93. public static $namespace = 'Database\\Factories\\';
  94. /**
  95. * The default model name resolver.
  96. *
  97. * @var callable
  98. */
  99. protected static $modelNameResolver;
  100. /**
  101. * The factory name resolver.
  102. *
  103. * @var callable
  104. */
  105. protected static $factoryNameResolver;
  106. /**
  107. * Create a new factory instance.
  108. *
  109. * @param int|null $count
  110. * @param \Illuminate\Support\Collection|null $states
  111. * @param \Illuminate\Support\Collection|null $has
  112. * @param \Illuminate\Support\Collection|null $for
  113. * @param \Illuminate\Support\Collection|null $afterMaking
  114. * @param \Illuminate\Support\Collection|null $afterCreating
  115. * @param string|null $connection
  116. * @param \Illuminate\Support\Collection|null $recycle
  117. * @return void
  118. */
  119. public function __construct($count = null,
  120. ?Collection $states = null,
  121. ?Collection $has = null,
  122. ?Collection $for = null,
  123. ?Collection $afterMaking = null,
  124. ?Collection $afterCreating = null,
  125. $connection = null,
  126. ?Collection $recycle = null)
  127. {
  128. $this->count = $count;
  129. $this->states = $states ?? new Collection;
  130. $this->has = $has ?? new Collection;
  131. $this->for = $for ?? new Collection;
  132. $this->afterMaking = $afterMaking ?? new Collection;
  133. $this->afterCreating = $afterCreating ?? new Collection;
  134. $this->connection = $connection;
  135. $this->recycle = $recycle ?? new Collection;
  136. $this->faker = $this->withFaker();
  137. }
  138. /**
  139. * Define the model's default state.
  140. *
  141. * @return array<string, mixed>
  142. */
  143. abstract public function definition();
  144. /**
  145. * Get a new factory instance for the given attributes.
  146. *
  147. * @param (callable(array<string, mixed>): array<string, mixed>)|array<string, mixed> $attributes
  148. * @return static
  149. */
  150. public static function new($attributes = [])
  151. {
  152. return (new static)->state($attributes)->configure();
  153. }
  154. /**
  155. * Get a new factory instance for the given number of models.
  156. *
  157. * @param int $count
  158. * @return static
  159. */
  160. public static function times(int $count)
  161. {
  162. return static::new()->count($count);
  163. }
  164. /**
  165. * Configure the factory.
  166. *
  167. * @return static
  168. */
  169. public function configure()
  170. {
  171. return $this;
  172. }
  173. /**
  174. * Get the raw attributes generated by the factory.
  175. *
  176. * @param (callable(array<string, mixed>): array<string, mixed>)|array<string, mixed> $attributes
  177. * @param \Illuminate\Database\Eloquent\Model|null $parent
  178. * @return array<int|string, mixed>
  179. */
  180. public function raw($attributes = [], ?Model $parent = null)
  181. {
  182. if ($this->count === null) {
  183. return $this->state($attributes)->getExpandedAttributes($parent);
  184. }
  185. return array_map(function () use ($attributes, $parent) {
  186. return $this->state($attributes)->getExpandedAttributes($parent);
  187. }, range(1, $this->count));
  188. }
  189. /**
  190. * Create a single model and persist it to the database.
  191. *
  192. * @param (callable(array<string, mixed>): array<string, mixed>)|array<string, mixed> $attributes
  193. * @return \Illuminate\Database\Eloquent\Model|TModel
  194. */
  195. public function createOne($attributes = [])
  196. {
  197. return $this->count(null)->create($attributes);
  198. }
  199. /**
  200. * Create a single model and persist it to the database without dispatching any model events.
  201. *
  202. * @param (callable(array<string, mixed>): array<string, mixed>)|array<string, mixed> $attributes
  203. * @return \Illuminate\Database\Eloquent\Model|TModel
  204. */
  205. public function createOneQuietly($attributes = [])
  206. {
  207. return $this->count(null)->createQuietly($attributes);
  208. }
  209. /**
  210. * Create a collection of models and persist them to the database.
  211. *
  212. * @param int|null|iterable<int, array<string, mixed>> $records
  213. * @return \Illuminate\Database\Eloquent\Collection<int, \Illuminate\Database\Eloquent\Model|TModel>
  214. */
  215. public function createMany(int|iterable|null $records = null)
  216. {
  217. $records ??= ($this->count ?? 1);
  218. $this->count = null;
  219. if (is_numeric($records)) {
  220. $records = array_fill(0, $records, []);
  221. }
  222. return new EloquentCollection(
  223. collect($records)->map(function ($record) {
  224. return $this->state($record)->create();
  225. })
  226. );
  227. }
  228. /**
  229. * Create a collection of models and persist them to the database without dispatching any model events.
  230. *
  231. * @param int|null|iterable<int, array<string, mixed>> $records
  232. * @return \Illuminate\Database\Eloquent\Collection<int, \Illuminate\Database\Eloquent\Model|TModel>
  233. */
  234. public function createManyQuietly(int|iterable|null $records = null)
  235. {
  236. return Model::withoutEvents(function () use ($records) {
  237. return $this->createMany($records);
  238. });
  239. }
  240. /**
  241. * Create a collection of models and persist them to the database.
  242. *
  243. * @param (callable(array<string, mixed>): array<string, mixed>)|array<string, mixed> $attributes
  244. * @param \Illuminate\Database\Eloquent\Model|null $parent
  245. * @return \Illuminate\Database\Eloquent\Collection<int, \Illuminate\Database\Eloquent\Model|TModel>|\Illuminate\Database\Eloquent\Model|TModel
  246. */
  247. public function create($attributes = [], ?Model $parent = null)
  248. {
  249. if (! empty($attributes)) {
  250. return $this->state($attributes)->create([], $parent);
  251. }
  252. $results = $this->make($attributes, $parent);
  253. if ($results instanceof Model) {
  254. $this->store(collect([$results]));
  255. $this->callAfterCreating(collect([$results]), $parent);
  256. } else {
  257. $this->store($results);
  258. $this->callAfterCreating($results, $parent);
  259. }
  260. return $results;
  261. }
  262. /**
  263. * Create a collection of models and persist them to the database without dispatching any model events.
  264. *
  265. * @param (callable(array<string, mixed>): array<string, mixed>)|array<string, mixed> $attributes
  266. * @param \Illuminate\Database\Eloquent\Model|null $parent
  267. * @return \Illuminate\Database\Eloquent\Collection<int, \Illuminate\Database\Eloquent\Model|TModel>|\Illuminate\Database\Eloquent\Model|TModel
  268. */
  269. public function createQuietly($attributes = [], ?Model $parent = null)
  270. {
  271. return Model::withoutEvents(function () use ($attributes, $parent) {
  272. return $this->create($attributes, $parent);
  273. });
  274. }
  275. /**
  276. * Create a callback that persists a model in the database when invoked.
  277. *
  278. * @param array<string, mixed> $attributes
  279. * @param \Illuminate\Database\Eloquent\Model|null $parent
  280. * @return \Closure(): (\Illuminate\Database\Eloquent\Collection<int, \Illuminate\Database\Eloquent\Model|TModel>|\Illuminate\Database\Eloquent\Model|TModel)
  281. */
  282. public function lazy(array $attributes = [], ?Model $parent = null)
  283. {
  284. return fn () => $this->create($attributes, $parent);
  285. }
  286. /**
  287. * Set the connection name on the results and store them.
  288. *
  289. * @param \Illuminate\Support\Collection $results
  290. * @return void
  291. */
  292. protected function store(Collection $results)
  293. {
  294. $results->each(function ($model) {
  295. if (! isset($this->connection)) {
  296. $model->setConnection($model->newQueryWithoutScopes()->getConnection()->getName());
  297. }
  298. $model->save();
  299. foreach ($model->getRelations() as $name => $items) {
  300. if ($items instanceof Enumerable && $items->isEmpty()) {
  301. $model->unsetRelation($name);
  302. }
  303. }
  304. $this->createChildren($model);
  305. });
  306. }
  307. /**
  308. * Create the children for the given model.
  309. *
  310. * @param \Illuminate\Database\Eloquent\Model $model
  311. * @return void
  312. */
  313. protected function createChildren(Model $model)
  314. {
  315. Model::unguarded(function () use ($model) {
  316. $this->has->each(function ($has) use ($model) {
  317. $has->recycle($this->recycle)->createFor($model);
  318. });
  319. });
  320. }
  321. /**
  322. * Make a single instance of the model.
  323. *
  324. * @param (callable(array<string, mixed>): array<string, mixed>)|array<string, mixed> $attributes
  325. * @return \Illuminate\Database\Eloquent\Model|TModel
  326. */
  327. public function makeOne($attributes = [])
  328. {
  329. return $this->count(null)->make($attributes);
  330. }
  331. /**
  332. * Create a collection of models.
  333. *
  334. * @param (callable(array<string, mixed>): array<string, mixed>)|array<string, mixed> $attributes
  335. * @param \Illuminate\Database\Eloquent\Model|null $parent
  336. * @return \Illuminate\Database\Eloquent\Collection<int, \Illuminate\Database\Eloquent\Model|TModel>|\Illuminate\Database\Eloquent\Model|TModel
  337. */
  338. public function make($attributes = [], ?Model $parent = null)
  339. {
  340. if (! empty($attributes)) {
  341. return $this->state($attributes)->make([], $parent);
  342. }
  343. if ($this->count === null) {
  344. return tap($this->makeInstance($parent), function ($instance) {
  345. $this->callAfterMaking(collect([$instance]));
  346. });
  347. }
  348. if ($this->count < 1) {
  349. return $this->newModel()->newCollection();
  350. }
  351. $instances = $this->newModel()->newCollection(array_map(function () use ($parent) {
  352. return $this->makeInstance($parent);
  353. }, range(1, $this->count)));
  354. $this->callAfterMaking($instances);
  355. return $instances;
  356. }
  357. /**
  358. * Make an instance of the model with the given attributes.
  359. *
  360. * @param \Illuminate\Database\Eloquent\Model|null $parent
  361. * @return \Illuminate\Database\Eloquent\Model
  362. */
  363. protected function makeInstance(?Model $parent)
  364. {
  365. return Model::unguarded(function () use ($parent) {
  366. return tap($this->newModel($this->getExpandedAttributes($parent)), function ($instance) {
  367. if (isset($this->connection)) {
  368. $instance->setConnection($this->connection);
  369. }
  370. });
  371. });
  372. }
  373. /**
  374. * Get a raw attributes array for the model.
  375. *
  376. * @param \Illuminate\Database\Eloquent\Model|null $parent
  377. * @return mixed
  378. */
  379. protected function getExpandedAttributes(?Model $parent)
  380. {
  381. return $this->expandAttributes($this->getRawAttributes($parent));
  382. }
  383. /**
  384. * Get the raw attributes for the model as an array.
  385. *
  386. * @param \Illuminate\Database\Eloquent\Model|null $parent
  387. * @return array
  388. */
  389. protected function getRawAttributes(?Model $parent)
  390. {
  391. return $this->states->pipe(function ($states) {
  392. return $this->for->isEmpty() ? $states : new Collection(array_merge([function () {
  393. return $this->parentResolvers();
  394. }], $states->all()));
  395. })->reduce(function ($carry, $state) use ($parent) {
  396. if ($state instanceof Closure) {
  397. $state = $state->bindTo($this);
  398. }
  399. return array_merge($carry, $state($carry, $parent));
  400. }, $this->definition());
  401. }
  402. /**
  403. * Create the parent relationship resolvers (as deferred Closures).
  404. *
  405. * @return array
  406. */
  407. protected function parentResolvers()
  408. {
  409. $model = $this->newModel();
  410. return $this->for->map(function (BelongsToRelationship $for) use ($model) {
  411. return $for->recycle($this->recycle)->attributesFor($model);
  412. })->collapse()->all();
  413. }
  414. /**
  415. * Expand all attributes to their underlying values.
  416. *
  417. * @param array $definition
  418. * @return array
  419. */
  420. protected function expandAttributes(array $definition)
  421. {
  422. return collect($definition)
  423. ->map($evaluateRelations = function ($attribute) {
  424. if ($attribute instanceof self) {
  425. $attribute = $this->getRandomRecycledModel($attribute->modelName())?->getKey()
  426. ?? $attribute->recycle($this->recycle)->create()->getKey();
  427. } elseif ($attribute instanceof Model) {
  428. $attribute = $attribute->getKey();
  429. }
  430. return $attribute;
  431. })
  432. ->map(function ($attribute, $key) use (&$definition, $evaluateRelations) {
  433. if (is_callable($attribute) && ! is_string($attribute) && ! is_array($attribute)) {
  434. $attribute = $attribute($definition);
  435. }
  436. $attribute = $evaluateRelations($attribute);
  437. $definition[$key] = $attribute;
  438. return $attribute;
  439. })
  440. ->all();
  441. }
  442. /**
  443. * Add a new state transformation to the model definition.
  444. *
  445. * @param (callable(array<string, mixed>, \Illuminate\Database\Eloquent\Model|null): array<string, mixed>)|array<string, mixed> $state
  446. * @return static
  447. */
  448. public function state($state)
  449. {
  450. return $this->newInstance([
  451. 'states' => $this->states->concat([
  452. is_callable($state) ? $state : function () use ($state) {
  453. return $state;
  454. },
  455. ]),
  456. ]);
  457. }
  458. /**
  459. * Set a single model attribute.
  460. *
  461. * @param string|int $key
  462. * @param mixed $value
  463. * @return static
  464. */
  465. public function set($key, $value)
  466. {
  467. return $this->state([$key => $value]);
  468. }
  469. /**
  470. * Add a new sequenced state transformation to the model definition.
  471. *
  472. * @param mixed ...$sequence
  473. * @return static
  474. */
  475. public function sequence(...$sequence)
  476. {
  477. return $this->state(new Sequence(...$sequence));
  478. }
  479. /**
  480. * Add a new sequenced state transformation to the model definition and update the pending creation count to the size of the sequence.
  481. *
  482. * @param array ...$sequence
  483. * @return static
  484. */
  485. public function forEachSequence(...$sequence)
  486. {
  487. return $this->state(new Sequence(...$sequence))->count(count($sequence));
  488. }
  489. /**
  490. * Add a new cross joined sequenced state transformation to the model definition.
  491. *
  492. * @param array ...$sequence
  493. * @return static
  494. */
  495. public function crossJoinSequence(...$sequence)
  496. {
  497. return $this->state(new CrossJoinSequence(...$sequence));
  498. }
  499. /**
  500. * Define a child relationship for the model.
  501. *
  502. * @param \Illuminate\Database\Eloquent\Factories\Factory $factory
  503. * @param string|null $relationship
  504. * @return static
  505. */
  506. public function has(self $factory, $relationship = null)
  507. {
  508. return $this->newInstance([
  509. 'has' => $this->has->concat([new Relationship(
  510. $factory, $relationship ?? $this->guessRelationship($factory->modelName())
  511. )]),
  512. ]);
  513. }
  514. /**
  515. * Attempt to guess the relationship name for a "has" relationship.
  516. *
  517. * @param string $related
  518. * @return string
  519. */
  520. protected function guessRelationship(string $related)
  521. {
  522. $guess = Str::camel(Str::plural(class_basename($related)));
  523. return method_exists($this->modelName(), $guess) ? $guess : Str::singular($guess);
  524. }
  525. /**
  526. * Define an attached relationship for the model.
  527. *
  528. * @param \Illuminate\Database\Eloquent\Factories\Factory|\Illuminate\Support\Collection|\Illuminate\Database\Eloquent\Model|array $factory
  529. * @param (callable(): array<string, mixed>)|array<string, mixed> $pivot
  530. * @param string|null $relationship
  531. * @return static
  532. */
  533. public function hasAttached($factory, $pivot = [], $relationship = null)
  534. {
  535. return $this->newInstance([
  536. 'has' => $this->has->concat([new BelongsToManyRelationship(
  537. $factory,
  538. $pivot,
  539. $relationship ?? Str::camel(Str::plural(class_basename(
  540. $factory instanceof Factory
  541. ? $factory->modelName()
  542. : Collection::wrap($factory)->first()
  543. )))
  544. )]),
  545. ]);
  546. }
  547. /**
  548. * Define a parent relationship for the model.
  549. *
  550. * @param \Illuminate\Database\Eloquent\Factories\Factory|\Illuminate\Database\Eloquent\Model $factory
  551. * @param string|null $relationship
  552. * @return static
  553. */
  554. public function for($factory, $relationship = null)
  555. {
  556. return $this->newInstance(['for' => $this->for->concat([new BelongsToRelationship(
  557. $factory,
  558. $relationship ?? Str::camel(class_basename(
  559. $factory instanceof Factory ? $factory->modelName() : $factory
  560. ))
  561. )])]);
  562. }
  563. /**
  564. * Provide model instances to use instead of any nested factory calls when creating relationships.
  565. *
  566. * @param \Illuminate\Database\Eloquent\Model|\Illuminate\Support\Collection|array $model
  567. * @return static
  568. */
  569. public function recycle($model)
  570. {
  571. // Group provided models by the type and merge them into existing recycle collection
  572. return $this->newInstance([
  573. 'recycle' => $this->recycle
  574. ->flatten()
  575. ->merge(
  576. Collection::wrap($model instanceof Model ? func_get_args() : $model)
  577. ->flatten()
  578. )->groupBy(fn ($model) => get_class($model)),
  579. ]);
  580. }
  581. /**
  582. * Retrieve a random model of a given type from previously provided models to recycle.
  583. *
  584. * @param string $modelClassName
  585. * @return \Illuminate\Database\Eloquent\Model|null
  586. */
  587. public function getRandomRecycledModel($modelClassName)
  588. {
  589. return $this->recycle->get($modelClassName)?->random();
  590. }
  591. /**
  592. * Add a new "after making" callback to the model definition.
  593. *
  594. * @param \Closure(\Illuminate\Database\Eloquent\Model|TModel): mixed $callback
  595. * @return static
  596. */
  597. public function afterMaking(Closure $callback)
  598. {
  599. return $this->newInstance(['afterMaking' => $this->afterMaking->concat([$callback])]);
  600. }
  601. /**
  602. * Add a new "after creating" callback to the model definition.
  603. *
  604. * @param \Closure(\Illuminate\Database\Eloquent\Model|TModel): mixed $callback
  605. * @return static
  606. */
  607. public function afterCreating(Closure $callback)
  608. {
  609. return $this->newInstance(['afterCreating' => $this->afterCreating->concat([$callback])]);
  610. }
  611. /**
  612. * Call the "after making" callbacks for the given model instances.
  613. *
  614. * @param \Illuminate\Support\Collection $instances
  615. * @return void
  616. */
  617. protected function callAfterMaking(Collection $instances)
  618. {
  619. $instances->each(function ($model) {
  620. $this->afterMaking->each(function ($callback) use ($model) {
  621. $callback($model);
  622. });
  623. });
  624. }
  625. /**
  626. * Call the "after creating" callbacks for the given model instances.
  627. *
  628. * @param \Illuminate\Support\Collection $instances
  629. * @param \Illuminate\Database\Eloquent\Model|null $parent
  630. * @return void
  631. */
  632. protected function callAfterCreating(Collection $instances, ?Model $parent = null)
  633. {
  634. $instances->each(function ($model) use ($parent) {
  635. $this->afterCreating->each(function ($callback) use ($model, $parent) {
  636. $callback($model, $parent);
  637. });
  638. });
  639. }
  640. /**
  641. * Specify how many models should be generated.
  642. *
  643. * @param int|null $count
  644. * @return static
  645. */
  646. public function count(?int $count)
  647. {
  648. return $this->newInstance(['count' => $count]);
  649. }
  650. /**
  651. * Specify the database connection that should be used to generate models.
  652. *
  653. * @param string $connection
  654. * @return static
  655. */
  656. public function connection(string $connection)
  657. {
  658. return $this->newInstance(['connection' => $connection]);
  659. }
  660. /**
  661. * Create a new instance of the factory builder with the given mutated properties.
  662. *
  663. * @param array $arguments
  664. * @return static
  665. */
  666. protected function newInstance(array $arguments = [])
  667. {
  668. return new static(...array_values(array_merge([
  669. 'count' => $this->count,
  670. 'states' => $this->states,
  671. 'has' => $this->has,
  672. 'for' => $this->for,
  673. 'afterMaking' => $this->afterMaking,
  674. 'afterCreating' => $this->afterCreating,
  675. 'connection' => $this->connection,
  676. 'recycle' => $this->recycle,
  677. ], $arguments)));
  678. }
  679. /**
  680. * Get a new model instance.
  681. *
  682. * @param array<string, mixed> $attributes
  683. * @return \Illuminate\Database\Eloquent\Model|TModel
  684. */
  685. public function newModel(array $attributes = [])
  686. {
  687. $model = $this->modelName();
  688. return new $model($attributes);
  689. }
  690. /**
  691. * Get the name of the model that is generated by the factory.
  692. *
  693. * @return class-string<\Illuminate\Database\Eloquent\Model|TModel>
  694. */
  695. public function modelName()
  696. {
  697. $resolver = static::$modelNameResolver ?? function (self $factory) {
  698. $namespacedFactoryBasename = Str::replaceLast(
  699. 'Factory', '', Str::replaceFirst(static::$namespace, '', get_class($factory))
  700. );
  701. $factoryBasename = Str::replaceLast('Factory', '', class_basename($factory));
  702. $appNamespace = static::appNamespace();
  703. return class_exists($appNamespace.'Models\\'.$namespacedFactoryBasename)
  704. ? $appNamespace.'Models\\'.$namespacedFactoryBasename
  705. : $appNamespace.$factoryBasename;
  706. };
  707. return $this->model ?? $resolver($this);
  708. }
  709. /**
  710. * Specify the callback that should be invoked to guess model names based on factory names.
  711. *
  712. * @param callable(self): class-string<\Illuminate\Database\Eloquent\Model|TModel> $callback
  713. * @return void
  714. */
  715. public static function guessModelNamesUsing(callable $callback)
  716. {
  717. static::$modelNameResolver = $callback;
  718. }
  719. /**
  720. * Specify the default namespace that contains the application's model factories.
  721. *
  722. * @param string $namespace
  723. * @return void
  724. */
  725. public static function useNamespace(string $namespace)
  726. {
  727. static::$namespace = $namespace;
  728. }
  729. /**
  730. * Get a new factory instance for the given model name.
  731. *
  732. * @param class-string<\Illuminate\Database\Eloquent\Model> $modelName
  733. * @return \Illuminate\Database\Eloquent\Factories\Factory
  734. */
  735. public static function factoryForModel(string $modelName)
  736. {
  737. $factory = static::resolveFactoryName($modelName);
  738. return $factory::new();
  739. }
  740. /**
  741. * Specify the callback that should be invoked to guess factory names based on dynamic relationship names.
  742. *
  743. * @param callable(class-string<\Illuminate\Database\Eloquent\Model>): class-string<\Illuminate\Database\Eloquent\Factories\Factory> $callback
  744. * @return void
  745. */
  746. public static function guessFactoryNamesUsing(callable $callback)
  747. {
  748. static::$factoryNameResolver = $callback;
  749. }
  750. /**
  751. * Get a new Faker instance.
  752. *
  753. * @return \Faker\Generator
  754. */
  755. protected function withFaker()
  756. {
  757. return Container::getInstance()->make(Generator::class);
  758. }
  759. /**
  760. * Get the factory name for the given model name.
  761. *
  762. * @param class-string<\Illuminate\Database\Eloquent\Model> $modelName
  763. * @return class-string<\Illuminate\Database\Eloquent\Factories\Factory>
  764. */
  765. public static function resolveFactoryName(string $modelName)
  766. {
  767. $resolver = static::$factoryNameResolver ?? function (string $modelName) {
  768. $appNamespace = static::appNamespace();
  769. $modelName = Str::startsWith($modelName, $appNamespace.'Models\\')
  770. ? Str::after($modelName, $appNamespace.'Models\\')
  771. : Str::after($modelName, $appNamespace);
  772. return static::$namespace.$modelName.'Factory';
  773. };
  774. return $resolver($modelName);
  775. }
  776. /**
  777. * Get the application namespace for the application.
  778. *
  779. * @return string
  780. */
  781. protected static function appNamespace()
  782. {
  783. try {
  784. return Container::getInstance()
  785. ->make(Application::class)
  786. ->getNamespace();
  787. } catch (Throwable) {
  788. return 'App\\';
  789. }
  790. }
  791. /**
  792. * Proxy dynamic factory methods onto their proper methods.
  793. *
  794. * @param string $method
  795. * @param array $parameters
  796. * @return mixed
  797. */
  798. public function __call($method, $parameters)
  799. {
  800. if (static::hasMacro($method)) {
  801. return $this->macroCall($method, $parameters);
  802. }
  803. if ($method === 'trashed' && in_array(SoftDeletes::class, class_uses_recursive($this->modelName()))) {
  804. return $this->state([
  805. $this->newModel()->getDeletedAtColumn() => $parameters[0] ?? Carbon::now()->subDay(),
  806. ]);
  807. }
  808. if (! Str::startsWith($method, ['for', 'has'])) {
  809. static::throwBadMethodCallException($method);
  810. }
  811. $relationship = Str::camel(Str::substr($method, 3));
  812. $relatedModel = get_class($this->newModel()->{$relationship}()->getRelated());
  813. if (method_exists($relatedModel, 'newFactory')) {
  814. $factory = $relatedModel::newFactory() ?? static::factoryForModel($relatedModel);
  815. } else {
  816. $factory = static::factoryForModel($relatedModel);
  817. }
  818. if (str_starts_with($method, 'for')) {
  819. return $this->for($factory->state($parameters[0] ?? []), $relationship);
  820. } elseif (str_starts_with($method, 'has')) {
  821. return $this->has(
  822. $factory
  823. ->count(is_numeric($parameters[0] ?? null) ? $parameters[0] : 1)
  824. ->state((is_callable($parameters[0] ?? null) || is_array($parameters[0] ?? null)) ? $parameters[0] : ($parameters[1] ?? [])),
  825. $relationship
  826. );
  827. }
  828. }
  829. }