feat: add CategoryImportController for bulk JSON import and export of categories
- Implemented export functionality to retrieve all rows from specified category tables. - Developed import functionality with strict validation and referential integrity checks. - Added error handling for various import scenarios including invalid formats and duplicate entries. - Introduced tests for import functionality to ensure correct behavior and validation.
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
namespace App\Tests\Category;
|
||||
|
||||
use App\Tests\ApiTestCase;
|
||||
use Doctrine\DBAL\Connection;
|
||||
|
||||
/**
|
||||
* POST /api/v1/admin/categories/{bundle}/import — bulk wipe+replace import.
|
||||
*
|
||||
* Guards the two behaviours the feature promises:
|
||||
* - strict validation: an invalid file is rejected whole, the table is untouched;
|
||||
* - referential integrity: self/cross references must resolve before any write.
|
||||
*
|
||||
* Runs against db_test (never reset), so every assertion is made against the
|
||||
* table the import owns, and the destructive cases verify the row count is the
|
||||
* SAME before and after a rejected import.
|
||||
*/
|
||||
class CategoryImportTest extends ApiTestCase
|
||||
{
|
||||
private function db(): Connection
|
||||
{
|
||||
return static::getContainer()->get(Connection::class);
|
||||
}
|
||||
|
||||
private function rowCount(string $table): int
|
||||
{
|
||||
return (int) $this->db()->fetchOne('SELECT COUNT(*) FROM ' . $table);
|
||||
}
|
||||
|
||||
public function testValidImportReplacesTheWholeTable(): void
|
||||
{
|
||||
$admin = $this->createUser(['ROLE_ADMIN']);
|
||||
|
||||
$body = $this->authJson('POST', '/api/v1/admin/categories/tags/import', $admin, [
|
||||
['id' => 90001, 'name' => 'تگ یک', 'slug' => 'imp-tag-1', 'status' => 1],
|
||||
['id' => 90002, 'name' => 'تگ دو', 'slug' => 'imp-tag-2', 'status' => 0],
|
||||
]);
|
||||
|
||||
$this->assertSame(200, $this->responseCode());
|
||||
$this->assertSame(2, $body['data']['imported'] ?? null);
|
||||
// wipe+replace: the table now holds exactly the imported rows
|
||||
$this->assertSame(2, $this->rowCount('tags'));
|
||||
$this->assertSame('imp-tag-1', $this->db()->fetchOne('SELECT slug FROM tags WHERE id = 90001'));
|
||||
}
|
||||
|
||||
public function testInvalidFileIsRejectedAndNothingIsWritten(): void
|
||||
{
|
||||
$admin = $this->createUser(['ROLE_ADMIN']);
|
||||
|
||||
// seed a known state, then attempt a bad import — count must not change
|
||||
$this->authJson('POST', '/api/v1/admin/categories/tags/import', $admin, [
|
||||
['id' => 91001, 'name' => 'پایه', 'slug' => 'seed-tag', 'status' => 1],
|
||||
]);
|
||||
$before = $this->rowCount('tags');
|
||||
|
||||
$body = $this->authJson('POST', '/api/v1/admin/categories/tags/import', $admin, [
|
||||
['id' => 1, 'name' => 'خوب', 'slug' => 'ok', 'status' => 1],
|
||||
['id' => 1, 'name' => '', 'slug' => 'ok', 'status' => 9], // dup id, empty name, dup slug, bad status
|
||||
]);
|
||||
|
||||
$this->assertSame(422, $this->responseCode());
|
||||
$this->assertNotEmpty($body['errors']);
|
||||
$this->assertSame($before, $this->rowCount('tags')); // table untouched
|
||||
}
|
||||
|
||||
public function testSpecialtyParentMustExistWithinTheFile(): void
|
||||
{
|
||||
$admin = $this->createUser(['ROLE_ADMIN']);
|
||||
|
||||
$body = $this->authJson('POST', '/api/v1/admin/categories/specialties/import', $admin, [
|
||||
['id' => 1, 'name' => 'ریشه', 'slug' => 'imp-root', 'status' => 1, 'weight' => 0, 'parent_id' => null],
|
||||
['id' => 2, 'name' => 'فرزند', 'slug' => 'imp-child', 'status' => 1, 'weight' => 0, 'parent_id' => 9999],
|
||||
]);
|
||||
|
||||
$this->assertSame(422, $this->responseCode());
|
||||
$fields = array_column($body['errors'], 'field');
|
||||
$this->assertContains('parent_id', $fields);
|
||||
}
|
||||
|
||||
public function testNonAdminIsForbidden(): void
|
||||
{
|
||||
$user = $this->createUser(['ROLE_USER']);
|
||||
$this->authJson('POST', '/api/v1/admin/categories/tags/import', $user, [
|
||||
['id' => 1, 'name' => 'x', 'slug' => 'x', 'status' => 1],
|
||||
]);
|
||||
$this->assertSame(403, $this->responseCode());
|
||||
}
|
||||
|
||||
public function testUnknownBundleIs404(): void
|
||||
{
|
||||
$admin = $this->createUser(['ROLE_ADMIN']);
|
||||
$this->authJson('POST', '/api/v1/admin/categories/nope/import', $admin, [
|
||||
['id' => 1, 'name' => 'x', 'slug' => 'x', 'status' => 1],
|
||||
]);
|
||||
$this->assertSame(404, $this->responseCode());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user