WithValidationTest.php 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077
  1. <?php
  2. namespace Maatwebsite\Excel\Tests\Concerns;
  3. use Illuminate\Database\Eloquent\Model;
  4. use Illuminate\Support\Collection;
  5. use Illuminate\Validation\Rule;
  6. use Maatwebsite\Excel\Concerns\Importable;
  7. use Maatwebsite\Excel\Concerns\OnEachRow;
  8. use Maatwebsite\Excel\Concerns\SkipsEmptyRows;
  9. use Maatwebsite\Excel\Concerns\ToArray;
  10. use Maatwebsite\Excel\Concerns\ToCollection;
  11. use Maatwebsite\Excel\Concerns\ToModel;
  12. use Maatwebsite\Excel\Concerns\WithBatchInserts;
  13. use Maatwebsite\Excel\Concerns\WithGroupedHeadingRow;
  14. use Maatwebsite\Excel\Concerns\WithHeadingRow;
  15. use Maatwebsite\Excel\Concerns\WithValidation;
  16. use Maatwebsite\Excel\Row;
  17. use Maatwebsite\Excel\Tests\Data\Stubs\Database\User;
  18. use Maatwebsite\Excel\Tests\TestCase;
  19. use Maatwebsite\Excel\Validators\ValidationException;
  20. use PHPUnit\Framework\Assert;
  21. class WithValidationTest extends TestCase
  22. {
  23. /**
  24. * Setup the test environment.
  25. */
  26. protected function setUp(): void
  27. {
  28. parent::setUp();
  29. $this->loadLaravelMigrations(['--database' => 'testing']);
  30. $this->loadMigrationsFrom(dirname(__DIR__) . '/Data/Stubs/Database/Migrations');
  31. }
  32. /**
  33. * @test
  34. */
  35. public function can_validate_rows()
  36. {
  37. $import = new class implements ToModel, WithValidation
  38. {
  39. use Importable;
  40. /**
  41. * @param array $row
  42. * @return Model|null
  43. */
  44. public function model(array $row)
  45. {
  46. return new User([
  47. 'name' => $row[0],
  48. 'email' => $row[1],
  49. 'password' => 'secret',
  50. ]);
  51. }
  52. /**
  53. * @return array
  54. */
  55. public function rules(): array
  56. {
  57. return [
  58. '1' => Rule::in(['patrick@maatwebsite.nl']),
  59. ];
  60. }
  61. };
  62. try {
  63. $import->import('import-users.xlsx');
  64. } catch (ValidationException $e) {
  65. $this->validateFailure($e, 2, '1', [
  66. 'The selected 1(field)? is invalid.',
  67. ]);
  68. $this->assertRegex(
  69. '/There was an error on row 2. The selected 1 (field)?is invalid./',
  70. $e->errors()[0][0]
  71. );
  72. }
  73. $this->assertInstanceOf(ValidationException::class, $e ?? null);
  74. }
  75. /**
  76. * @test
  77. */
  78. public function can_validate_rows_with_closure_validation_rules()
  79. {
  80. $import = new class implements ToModel, WithValidation
  81. {
  82. use Importable;
  83. /**
  84. * @param array $row
  85. * @return Model|null
  86. */
  87. public function model(array $row)
  88. {
  89. return new User([
  90. 'name' => $row[0],
  91. 'email' => $row[1],
  92. 'password' => 'secret',
  93. ]);
  94. }
  95. /**
  96. * @return array
  97. */
  98. public function rules(): array
  99. {
  100. return [
  101. '1' => function ($attribute, $value, $onFail) {
  102. if ($value !== 'patrick@maatwebsite.nl') {
  103. $onFail(sprintf('Value in column 1 is not an allowed e-mail.'));
  104. }
  105. },
  106. ];
  107. }
  108. };
  109. try {
  110. $import->import('import-users.xlsx');
  111. } catch (ValidationException $e) {
  112. $this->validateFailure($e, 2, '1', [
  113. 'Value in column 1 is not an allowed e-mail.',
  114. ]);
  115. $this->assertRegex(
  116. '/There was an error on row 2. Value in column 1 is not an allowed e-mail./',
  117. $e->errors()[0][0]
  118. );
  119. }
  120. $this->assertInstanceOf(ValidationException::class, $e ?? null);
  121. }
  122. /**
  123. * @test
  124. */
  125. public function can_validate_rows_with_custom_validation_rule_objects()
  126. {
  127. $import = new class implements ToModel, WithValidation
  128. {
  129. use Importable;
  130. /**
  131. * @param array $row
  132. * @return Model|null
  133. */
  134. public function model(array $row)
  135. {
  136. return new User([
  137. 'name' => $row[0],
  138. 'email' => $row[1],
  139. 'password' => 'secret',
  140. ]);
  141. }
  142. /**
  143. * @return array
  144. */
  145. public function rules(): array
  146. {
  147. return [
  148. '1' => new class implements \Illuminate\Contracts\Validation\Rule
  149. {
  150. /**
  151. * @param string $attribute
  152. * @param mixed $value
  153. * @return bool
  154. */
  155. public function passes($attribute, $value)
  156. {
  157. return $value === 'patrick@maatwebsite.nl';
  158. }
  159. /**
  160. * Get the validation error message.
  161. *
  162. * @return string|array
  163. */
  164. public function message()
  165. {
  166. return 'Value is not an allowed e-mail.';
  167. }
  168. },
  169. ];
  170. }
  171. };
  172. try {
  173. $import->import('import-users.xlsx');
  174. } catch (ValidationException $e) {
  175. $this->validateFailure($e, 2, '1', [
  176. 'Value is not an allowed e-mail.',
  177. ]);
  178. $this->assertRegex(
  179. '/There was an error on row 2. Value is not an allowed e-mail./',
  180. $e->errors()[0][0]
  181. );
  182. }
  183. $this->assertInstanceOf(ValidationException::class, $e ?? null);
  184. }
  185. /**
  186. * @test
  187. */
  188. public function can_validate_rows_with_conditionality()
  189. {
  190. $import = new class implements ToModel, WithValidation
  191. {
  192. use Importable;
  193. /**
  194. * @param array $row
  195. * @return Model|null
  196. */
  197. public function model(array $row)
  198. {
  199. return new User([
  200. 'name' => $row[0],
  201. 'email' => $row[1],
  202. 'password' => 'secret',
  203. ]);
  204. }
  205. /**
  206. * @return array
  207. */
  208. public function rules(): array
  209. {
  210. return [
  211. 'conditional_required_column' => 'required_if:1,patrick@maatwebsite.nl',
  212. ];
  213. }
  214. };
  215. try {
  216. $import->import('import-users.xlsx');
  217. } catch (ValidationException $e) {
  218. $this->validateFailure($e, 1, 'conditional_required_column', [
  219. 'The conditional_required_column field is required when 1.1 is patrick@maatwebsite.nl.',
  220. ]);
  221. }
  222. $this->assertInstanceOf(ValidationException::class, $e ?? null);
  223. }
  224. /**
  225. * @test
  226. */
  227. public function can_validate_rows_with_unless_conditionality()
  228. {
  229. $import = new class implements ToModel, WithValidation
  230. {
  231. use Importable;
  232. /**
  233. * @param array $row
  234. * @return Model|null
  235. */
  236. public function model(array $row)
  237. {
  238. return new User([
  239. 'name' => $row[0],
  240. 'email' => $row[1],
  241. 'password' => 'secret',
  242. ]);
  243. }
  244. /**
  245. * @return array
  246. */
  247. public function rules(): array
  248. {
  249. return [
  250. 'conditional_required_unless_column' => 'required_unless:1,patrick@maatwebsite.nl',
  251. ];
  252. }
  253. };
  254. try {
  255. $import->import('import-users.xlsx');
  256. } catch (ValidationException $e) {
  257. $this->validateFailure($e, 2, 'conditional_required_unless_column', [
  258. 'The conditional_required_unless_column field is required unless 2.1 is in patrick@maatwebsite.nl.',
  259. ]);
  260. }
  261. $this->assertInstanceOf(ValidationException::class, $e ?? null);
  262. }
  263. /**
  264. * @test
  265. */
  266. public function can_validate_with_custom_attributes()
  267. {
  268. $import = new class implements ToModel, WithValidation
  269. {
  270. use Importable;
  271. /**
  272. * @param array $row
  273. * @return Model|null
  274. */
  275. public function model(array $row)
  276. {
  277. return new User([
  278. 'name' => $row[0],
  279. 'email' => $row[1],
  280. 'password' => 'secret',
  281. ]);
  282. }
  283. /**
  284. * @return array
  285. */
  286. public function rules(): array
  287. {
  288. return [
  289. '1' => Rule::in(['patrick@maatwebsite.nl']),
  290. ];
  291. }
  292. /**
  293. * @return array
  294. */
  295. public function customValidationAttributes()
  296. {
  297. return ['1' => 'email'];
  298. }
  299. };
  300. try {
  301. $import->import('import-users.xlsx');
  302. } catch (ValidationException $e) {
  303. $this->validateFailure($e, 2, 'email', [
  304. 'The selected email is invalid.',
  305. ]);
  306. }
  307. $this->assertInstanceOf(ValidationException::class, $e ?? null);
  308. }
  309. /**
  310. * @test
  311. */
  312. public function can_validate_with_custom_message()
  313. {
  314. $import = new class implements ToModel, WithValidation
  315. {
  316. use Importable;
  317. /**
  318. * @param array $row
  319. * @return Model|null
  320. */
  321. public function model(array $row)
  322. {
  323. return new User([
  324. 'name' => $row[0],
  325. 'email' => $row[1],
  326. 'password' => 'secret',
  327. ]);
  328. }
  329. /**
  330. * @return array
  331. */
  332. public function rules(): array
  333. {
  334. return [
  335. '1' => Rule::in(['patrick@maatwebsite.nl']),
  336. ];
  337. }
  338. /**
  339. * @return array
  340. */
  341. public function customValidationMessages()
  342. {
  343. return [
  344. '1.in' => 'Custom message for :attribute.',
  345. ];
  346. }
  347. };
  348. try {
  349. $import->import('import-users.xlsx');
  350. } catch (ValidationException $e) {
  351. $this->validateFailure($e, 2, '1', [
  352. 'Custom message for 1.',
  353. ]);
  354. }
  355. $this->assertInstanceOf(ValidationException::class, $e ?? null);
  356. }
  357. /**
  358. * @test
  359. */
  360. public function can_validate_rows_with_headings()
  361. {
  362. $import = new class implements ToModel, WithHeadingRow, WithValidation
  363. {
  364. use Importable;
  365. /**
  366. * @param array $row
  367. * @return Model|null
  368. */
  369. public function model(array $row)
  370. {
  371. return new User([
  372. 'name' => $row['name'],
  373. 'email' => $row['email'],
  374. 'password' => 'secret',
  375. ]);
  376. }
  377. /**
  378. * @return array
  379. */
  380. public function rules(): array
  381. {
  382. return [
  383. 'email' => Rule::in(['patrick@maatwebsite.nl']),
  384. ];
  385. }
  386. };
  387. try {
  388. $import->import('import-users-with-headings.xlsx');
  389. } catch (ValidationException $e) {
  390. $this->validateFailure($e, 3, 'email', [
  391. 'The selected email is invalid.',
  392. ]);
  393. }
  394. $this->assertInstanceOf(ValidationException::class, $e ?? null);
  395. }
  396. /**
  397. * @test
  398. */
  399. public function can_validate_rows_with_grouped_headings()
  400. {
  401. $import = new class implements ToModel, WithGroupedHeadingRow, WithValidation
  402. {
  403. use Importable;
  404. /**
  405. * Prepare the data for validation.
  406. *
  407. * @param array $row
  408. * @param int $index
  409. * @return array
  410. */
  411. public function prepareForValidation(array $row, int $index)
  412. {
  413. if ($index === 2) {
  414. Assert::assertIsArray($row['options']);
  415. $row['options'] = 'not an array';
  416. }
  417. return $row;
  418. }
  419. /**
  420. * @param array $row
  421. * @return Model|null
  422. */
  423. public function model(array $row)
  424. {
  425. return new User([
  426. 'name' => $row['name'],
  427. 'email' => $row['email'],
  428. 'password' => 'secret',
  429. 'options' => $row['options'],
  430. ]);
  431. }
  432. /**
  433. * @return array
  434. */
  435. public function rules(): array
  436. {
  437. return [
  438. 'options' => 'array',
  439. ];
  440. }
  441. };
  442. try {
  443. $import->import('import-users-with-grouped-headers.xlsx');
  444. } catch (ValidationException $e) {
  445. $this->validateFailure($e, 2, 'options', [
  446. 'The options( field)? must be an array.',
  447. ]);
  448. }
  449. $this->assertInstanceOf(ValidationException::class, $e ?? null);
  450. }
  451. /**
  452. * @test
  453. */
  454. public function can_validate_rows_in_batches()
  455. {
  456. $import = new class implements ToModel, WithHeadingRow, WithBatchInserts, WithValidation
  457. {
  458. use Importable;
  459. /**
  460. * @param array $row
  461. * @return Model|null
  462. */
  463. public function model(array $row)
  464. {
  465. return new User([
  466. 'name' => $row['name'],
  467. 'email' => $row['email'],
  468. 'password' => 'secret',
  469. ]);
  470. }
  471. /**
  472. * @return int
  473. */
  474. public function batchSize(): int
  475. {
  476. return 2;
  477. }
  478. /**
  479. * @return array
  480. */
  481. public function rules(): array
  482. {
  483. return [
  484. 'email' => Rule::in(['patrick@maatwebsite.nl']),
  485. ];
  486. }
  487. };
  488. try {
  489. $import->import('import-users-with-headings.xlsx');
  490. } catch (ValidationException $e) {
  491. $this->validateFailure($e, 3, 'email', [
  492. 'The selected email is invalid.',
  493. ]);
  494. }
  495. $this->assertInstanceOf(ValidationException::class, $e ?? null);
  496. }
  497. /**
  498. * @test
  499. */
  500. public function can_validate_using_oneachrow()
  501. {
  502. $import = new class implements OnEachRow, WithHeadingRow, WithValidation
  503. {
  504. use Importable;
  505. /**
  506. * @param Row $row
  507. * @return Model|null
  508. */
  509. public function onRow(Row $row)
  510. {
  511. $values = $row->toArray();
  512. return new User([
  513. 'name' => $values['name'],
  514. 'email' => $values['email'],
  515. 'password' => 'secret',
  516. ]);
  517. }
  518. /**
  519. * @return array
  520. */
  521. public function rules(): array
  522. {
  523. return [
  524. 'email' => Rule::in(['patrick@maatwebsite.nl']),
  525. ];
  526. }
  527. };
  528. try {
  529. $import->import('import-users-with-headings.xlsx');
  530. } catch (ValidationException $e) {
  531. $this->validateFailure($e, 3, 'email', [
  532. 'The selected email is invalid.',
  533. ]);
  534. }
  535. $this->assertInstanceOf(ValidationException::class, $e ?? null);
  536. }
  537. /**
  538. * @test
  539. */
  540. public function can_validate_using_collection()
  541. {
  542. $import = new class implements ToCollection, WithHeadingRow, WithValidation
  543. {
  544. use Importable;
  545. public function collection(Collection $rows)
  546. {
  547. //
  548. }
  549. /**
  550. * @return array
  551. */
  552. public function rules(): array
  553. {
  554. return [
  555. 'email' => Rule::in(['patrick@maatwebsite.nl']),
  556. ];
  557. }
  558. };
  559. try {
  560. $import->import('import-users-with-headings.xlsx');
  561. } catch (ValidationException $e) {
  562. $this->validateFailure($e, 3, 'email', [
  563. 'The selected email is invalid.',
  564. ]);
  565. }
  566. $this->assertInstanceOf(ValidationException::class, $e ?? null);
  567. }
  568. /**
  569. * @test
  570. */
  571. public function can_validate_using_array()
  572. {
  573. $import = new class implements ToArray, WithHeadingRow, WithValidation
  574. {
  575. use Importable;
  576. public function array(array $rows)
  577. {
  578. //
  579. }
  580. /**
  581. * @return array
  582. */
  583. public function rules(): array
  584. {
  585. return [
  586. 'email' => Rule::in(['patrick@maatwebsite.nl']),
  587. ];
  588. }
  589. };
  590. try {
  591. $import->import('import-users-with-headings.xlsx');
  592. } catch (ValidationException $e) {
  593. $this->validateFailure($e, 3, 'email', [
  594. 'The selected email is invalid.',
  595. ]);
  596. }
  597. $this->assertInstanceOf(ValidationException::class, $e ?? null);
  598. }
  599. /**
  600. * @test
  601. */
  602. public function can_configure_validator()
  603. {
  604. $import = new class implements ToModel, WithValidation
  605. {
  606. use Importable;
  607. /**
  608. * @param array $row
  609. * @return Model|null
  610. */
  611. public function model(array $row)
  612. {
  613. return new User([
  614. 'name' => $row[0],
  615. 'email' => $row[1],
  616. 'password' => 'secret',
  617. ]);
  618. }
  619. /**
  620. * @return array
  621. */
  622. public function rules(): array
  623. {
  624. return [
  625. '1' => 'email',
  626. ];
  627. }
  628. /**
  629. * Configure the validator.
  630. *
  631. * @param \Illuminate\Contracts\Validation\Validator $validator
  632. * @return void
  633. */
  634. public function withValidator($validator)
  635. {
  636. $validator->sometimes('*.1', Rule::in(['patrick@maatwebsite.nl']), function () {
  637. return true;
  638. });
  639. }
  640. };
  641. try {
  642. $import->import('import-users.xlsx');
  643. } catch (ValidationException $e) {
  644. $this->validateFailure($e, 2, '1', [
  645. 'The selected 1 is invalid.',
  646. ]);
  647. $this->assertRegex(
  648. '/There was an error on row 2. The selected 1 (field)?is invalid./',
  649. $e->errors()[0][0]
  650. );
  651. }
  652. $this->assertInstanceOf(ValidationException::class, $e ?? null);
  653. }
  654. /**
  655. * @test
  656. */
  657. public function can_prepare_using_toarray()
  658. {
  659. $import = new class implements ToArray, WithValidation
  660. {
  661. use Importable;
  662. /**
  663. * @return array
  664. */
  665. public function rules(): array
  666. {
  667. return [
  668. '1' => 'email',
  669. ];
  670. }
  671. /**
  672. * Prepare the data for validation.
  673. *
  674. * @param array $row
  675. * @param int $index
  676. * @return array
  677. */
  678. public function prepareForValidation(array $row, int $index)
  679. {
  680. if ($index === 2) {
  681. $row[1] = 'not an email';
  682. }
  683. return $row;
  684. }
  685. /**
  686. * @param array $array
  687. * @return array
  688. */
  689. public function array(array $array)
  690. {
  691. return [];
  692. }
  693. };
  694. try {
  695. $import->import('import-users.xlsx');
  696. } catch (ValidationException $e) {
  697. $this->validateFailure($e, 2, '1', [
  698. 'The 1( field)? must be a valid email address.',
  699. ]);
  700. $this->assertRegex(
  701. '/There was an error on row 2. The 1( field)? must be a valid email address./',
  702. $e->errors()[0][0]
  703. );
  704. }
  705. $this->assertInstanceOf(ValidationException::class, $e ?? null);
  706. }
  707. /**
  708. * @test
  709. */
  710. public function can_prepare_using_tocollection()
  711. {
  712. $import = new class implements ToCollection, WithValidation
  713. {
  714. use Importable;
  715. /**
  716. * @return array
  717. */
  718. public function rules(): array
  719. {
  720. return [
  721. '1' => 'email',
  722. ];
  723. }
  724. /**
  725. * Prepare the data for validation.
  726. *
  727. * @param array $row
  728. * @param int $index
  729. * @return array
  730. */
  731. public function prepareForValidation(array $row, int $index)
  732. {
  733. if ($index === 2) {
  734. $row[1] = 'not an email';
  735. }
  736. return $row;
  737. }
  738. /**
  739. * @param \Illuminate\Support\Collection $collection
  740. * @return mixed
  741. */
  742. public function collection(Collection $collection)
  743. {
  744. return collect();
  745. }
  746. };
  747. try {
  748. $import->import('import-users.xlsx');
  749. } catch (ValidationException $e) {
  750. $this->validateFailure($e, 2, '1', [
  751. 'The 1( field)? must be a valid email address.',
  752. ]);
  753. $this->assertRegex(
  754. '/There was an error on row 2. The 1( field)? must be a valid email address./',
  755. $e->errors()[0][0]
  756. );
  757. }
  758. $this->assertInstanceOf(ValidationException::class, $e ?? null);
  759. }
  760. /**
  761. * @test
  762. */
  763. public function can_prepare_using_tomodel()
  764. {
  765. $import = new class implements ToModel, WithValidation
  766. {
  767. use Importable;
  768. /**
  769. * @return array
  770. */
  771. public function rules(): array
  772. {
  773. return [
  774. '1' => 'email',
  775. ];
  776. }
  777. /**
  778. * Prepare the data for validation.
  779. *
  780. * @param array $row
  781. * @param int $index
  782. * @return array
  783. */
  784. public function prepareForValidation(array $row, int $index)
  785. {
  786. if ($index === 2) {
  787. $row[1] = 'not an email';
  788. }
  789. return $row;
  790. }
  791. /**
  792. * @param array $row
  793. * @return \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Model[]|null
  794. */
  795. public function model(array $row)
  796. {
  797. return new User([
  798. 'name' => $row[0],
  799. 'email' => $row[1],
  800. 'password' => 'secret',
  801. ]);
  802. }
  803. };
  804. try {
  805. $import->import('import-users.xlsx');
  806. } catch (ValidationException $e) {
  807. $this->validateFailure($e, 2, '1', [
  808. 'The 1( field)? must be a valid email address.',
  809. ]);
  810. $this->assertRegex(
  811. '/There was an error on row 2. The 1( field)? must be a valid email address./',
  812. $e->errors()[0][0]
  813. );
  814. }
  815. $this->assertInstanceOf(ValidationException::class, $e ?? null);
  816. }
  817. /**
  818. * @test
  819. */
  820. public function can_prepare_using_oneachrow()
  821. {
  822. $import = new class implements OnEachRow, WithValidation
  823. {
  824. use Importable;
  825. /**
  826. * @return array
  827. */
  828. public function rules(): array
  829. {
  830. return [
  831. '1' => 'email',
  832. ];
  833. }
  834. /**
  835. * Prepare the data for validation.
  836. *
  837. * @param array $row
  838. * @param int $index
  839. * @return array
  840. */
  841. public function prepareForValidation(array $row, int $index)
  842. {
  843. if ($index === 2) {
  844. $row[1] = 'not an email';
  845. }
  846. return $row;
  847. }
  848. /**
  849. * @param \Maatwebsite\Excel\Row $row
  850. * @return void
  851. */
  852. public function onRow(Row $row)
  853. {
  854. User::query()->create([
  855. 'name' => $row[0],
  856. 'email' => $row[1],
  857. 'password' => 'secret',
  858. ]);
  859. }
  860. };
  861. try {
  862. $import->import('import-users.xlsx');
  863. } catch (ValidationException $e) {
  864. $this->validateFailure($e, 2, '1', [
  865. 'The 1( field)? must be a valid email address.',
  866. ]);
  867. $this->assertRegex(
  868. '/There was an error on row 2. The 1( field)? must be a valid email address./',
  869. $e->errors()[0][0]
  870. );
  871. }
  872. $this->assertInstanceOf(ValidationException::class, $e ?? null);
  873. }
  874. /**
  875. * @test
  876. */
  877. public function can_prepare_using_skipsemptyrows()
  878. {
  879. $import = new class implements OnEachRow, WithValidation, SkipsEmptyRows
  880. {
  881. use Importable;
  882. /**
  883. * @return array
  884. */
  885. public function rules(): array
  886. {
  887. return [
  888. '1' => 'email',
  889. ];
  890. }
  891. /**
  892. * Prepare the data for validation.
  893. *
  894. * @param array $row
  895. * @param int $index
  896. * @return array
  897. */
  898. public function prepareForValidation(array $row, int $index)
  899. {
  900. if ($index === 2) {
  901. $row[1] = 'not an email';
  902. }
  903. return $row;
  904. }
  905. /**
  906. * @param \Maatwebsite\Excel\Row $row
  907. * @return void
  908. */
  909. public function onRow(Row $row)
  910. {
  911. User::query()->create([
  912. 'name' => $row[0],
  913. 'email' => $row[1],
  914. 'password' => 'secret',
  915. ]);
  916. }
  917. };
  918. try {
  919. $import->import('import-users.xlsx');
  920. } catch (ValidationException $e) {
  921. $this->validateFailure($e, 2, '1', [
  922. 'The 1( field)? must be a valid email address.',
  923. ]);
  924. $this->assertRegex(
  925. '/There was an error on row 2. The 1( field)? must be a valid email address./',
  926. $e->errors()[0][0]
  927. );
  928. }
  929. $this->assertInstanceOf(ValidationException::class, $e ?? null);
  930. }
  931. /**
  932. * @param ValidationException $e
  933. * @param int $row
  934. * @param string $attribute
  935. * @param array $messages
  936. */
  937. private function validateFailure(ValidationException $e, int $row, string $attribute, array $messages)
  938. {
  939. $failures = $e->failures();
  940. $failure = head($failures);
  941. $this->assertEquals($row, $failure->row());
  942. $this->assertEquals($attribute, $failure->attribute());
  943. $this->assertEquals($row, $failure->jsonSerialize()['row']);
  944. $this->assertEquals($attribute, $failure->jsonSerialize()['attribute']);
  945. $this->assertRegex('/' . $messages[0] . '/', $failure->errors()[0]);
  946. $this->assertRegex('/' . $messages[0] . '/', $failure->jsonSerialize()['errors'][0]);
  947. }
  948. }