A Symfony bundle that extends EasyAdmin to work with any data source β files, APIs, arrays, or custom iterators β without requiring Doctrine ORM.
- ποΈ Non-Doctrine CRUD β Use EasyAdmin's powerful interface for files, APIs, or any iterable data
- β‘ Batch Actions β Full support for EasyAdmin batch actions with automatic DTO resolution
- π¨ EasyAdmin Fields β Reuse any EasyAdmin field types (
IdField,TextField, etc.) - π§ Custom Actions β Create custom actions and batch operations
- π― Simple Integration β Extend
AbstractMapperControllerand implementMapperControllerInterface
- PHP 8.1 or higher
- Symfony 6.1 or higher
- EasyAdmin Bundle 4.x
composer require wertelko/easyadmin-mapperAdd the bundle to your config/bundles.php:
<?php
return [
// ... other bundles
Wertelko\EasyadminMapperBundle\EasyadminMapperBundle::class => ['all' => true],
];Create a controller that extends AbstractMapperController and implements MapperControllerInterface:
<?php
namespace App\Controller\Admin;
use EasyCorp\Bundle\EasyAdminBundle\Config\Action;
use EasyCorp\Bundle\EasyAdminBundle\Config\Actions;
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
use EasyCorp\Bundle\EasyAdminBundle\Dto\BatchActionDto;
use EasyCorp\Bundle\EasyAdminBundle\Field\DateTimeField;
use EasyCorp\Bundle\EasyAdminBundle\Field\IdField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
use Symfony\Component\Finder\Finder;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
use Wertelko\EasyadminMapperBundle\Contract\MapperControllerInterface;
use Wertelko\EasyadminMapperBundle\Controller\AbstractMapperController;
class TestController extends AbstractMapperController implements MapperControllerInterface
{
public function configureActions(Actions $actions): Actions
{
return parent::configureActions($actions)
->add(Crud::PAGE_INDEX,
Action::new('removeFile', 'Delete')
->createAsBatchAction()
->linkToRoute('admin_files')
);
}
public function configureFields(string $pageName): iterable
{
yield IdField::new('pathname');
yield TextField::new('size')->formatValue(fn($value) => $this->formatBytes($value));
yield DateTimeField::new('mtime', 'Modified');
}
#[Route('/admin/files', name: 'admin_files')]
public function index(BatchActionDto $actionDto): Response
{
// Handle batch actions
if ($actionDto->getName()) {
return call_user_func([$this, $actionDto->getName()], $actionDto);
}
// Load your data from any source
$finder = new Finder();
$files = $finder->files()->in($this->getParameter('kernel.cache_dir'));
// Render the EasyAdmin table
return $this->renderTable($files, 'Cache files');
}
public function removeFile(BatchActionDto $actionDto): Response
{
foreach ($actionDto->getEntityIds() as $filename) {
$path = $this->getParameter('kernel.cache_dir') . $filename;
if (file_exists($path)) {
unlink($path);
}
}
$this->addFlash('success', sprintf('%d files deleted.', count($actionDto->getEntityIds())));
return $this->redirectToRoute('admin_files');
}
private function formatBytes(int $bytes): string
{
$units = ['B', 'KB', 'MB', 'GB'];
$i = 0;
while ($bytes >= 1024 && $i < count($units) - 1) {
$bytes /= 1024;
$i++;
}
return round($bytes, 2) . ' ' . $units[$i];
}
}<?php
namespace App\Controller\Admin;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
use EasyCorp\Bundle\EasyAdminBundle\Field\EmailField;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Contracts\HttpClient\HttpClientInterface;
use Wertelko\EasyadminMapperBundle\Contract\MapperControllerInterface;
use Wertelko\EasyadminMapperBundle\Controller\AbstractMapperController;
class UsersController extends AbstractMapperController implements MapperControllerInterface
{
public function __construct(
private HttpClientInterface $httpClient
) {}
public function configureFields(string $pageName): iterable
{
yield IdField::new('id');
yield TextField::new('name');
yield EmailField::new('email');
}
#[Route('/admin/api-users', name: 'admin_api_users')]
public function index(): Response
{
$response = $this->httpClient->request('GET', 'https://api.example.com/users');
$users = $response->toArray();
return $this->renderTable($users);
}
}public function configureFields(string $pageName): iterable
{
yield IdField::new('id');
yield TextField::new('level');
yield DateTimeField::new('message');
}
#[Route('/admin/logs', name: 'admin_logs')]
public function logs(): Response
{
$logs = [
['id' => 1, 'level' => 'ERROR', 'message' => 'Database connection failed'],
['id' => 2, 'level' => 'WARNING', 'message' => 'Disk space low'],
['id' => 3, 'level' => 'INFO', 'message' => 'Cache cleared'],
];
return $this->renderTable($logs);
}The bundle provides:
AbstractMapperControllerβ Base controller withrenderTable()method that converts any iterable/array into an EasyAdmin-compatible tableMapperControllerInterfaceβ Marker interface that identifies your controllers as mapper controllersBatchActionDtoValueResolverβ Custom argument resolver that injectsBatchActionDtointo your controller actions for handling batch operations
The bundle automatically registers its services. No additional configuration is required.
This bundle is released under the MIT License.
Contributions are welcome! Please feel free to submit a Pull Request.
If you encounter any issues or have questions, please open an issue on GitHub.