idct/adminata
Adminata is a Laravel package for admin data management, offering utilities to organize and expose backend data for administrative interfaces. It integrates with Eloquent models to streamline common admin panel tasks.
Reality check before you type composer require. This is a Symfony bundle, not a Laravel package. There is no service provider, no config/adminata.php, no Blade views, no Eloquent driver. A Laravel developer "leverages" it in exactly two ways: (a) you are working inside a Symfony application (or a sidecar admin service) and this is the back-office layer, or (b) you are reading it to steal patterns. If you were hoping to drop an admin panel into a Laravel app, stop here — the integration path is a separate Symfony container behind a reverse proxy, not a package install.
Minimal steps (Symfony host app):
composer require idct/adminata
Before anything else, prove the conflict surface is clean — this bundle is a hard fork of the Sonata Admin stack and declares conflicts against it:
composer why-not sonata-project/admin-bundle
composer show --tree | grep -i sonata # any transitive Sonata dep will block or poison this
Then:
config/bundles.php (namespace is IDCT\Adminata\...; check vendor/idct/adminata/src/ for the exact bundle class names — the fork ships several: admin, block, doctrine, exporter, form, twig extensions).sonata_admin:. Confirm with bin/console config:dump-reference <bundle-alias> — do not copy-paste Sonata docs.@import "tailwindcss"; + @theme), so there is likely no tailwind.config.js to edit. You need your app's CSS entrypoint to @source the vendor templates or the styling renders as unstyled HTML.^/admin behind ROLE_ADMIN (or whatever role the dashboards declare). Nothing works until the security config matches the route prefix.bin/console list | grep -i admin — the fork very likely retains sonata:admin:generate semantics under a new name (adminata:admin:generate or similar). Generate an admin for an existing Doctrine entity, register the service, hit /admin.Where to look first, in order: the bundle's Resources/config/ (service ids and tags — the fork almost certainly renamed sonata.admin tags), Resources/views/ (override paths), src/Admin/AbstractAdmin.php (the contract you'll subclass), and the CHANGELOG/UPGRADE files if present — a hard fork usually documents its divergences there.
First real use case: a back office for a Doctrine entity you already have — list with filters, create/edit form, delete, CSV export. That exercises the whole stack (admin → doctrine → form → exporter → twig) and tells you within an hour whether the fork is viable.
One admin class per entity, registered as a tagged service. The Sonata shape survives the fork: subclass the abstract admin, implement the four configure* hooks.
namespace App\Admin;
use IDCT\Adminata\Admin\AbstractAdmin; // verify exact FQCN in vendor/
use IDCT\Adminata\Form\...;
use IDCT\Adminata\Datagrid\...;
final class OrderAdmin extends AbstractAdmin
{
protected function configureFormFields(FormMapper $form): void
{
$form->with('Order', ['class' => 'col-md-8'])
->add('reference')
->add('status')
->end()
->with('Meta', ['class' => 'col-md-4'])
->add('createdAt')
->end();
}
protected function configureListFields(ListMapper $list): void
{
$list->addIdentifier('reference')
->add('status')
->add('total')
->add('createdAt', null, ['format' => 'Y-m-d H:i'])
->add(ListMapper::NAME_ACTIONS, null, ['actions' => ['edit' => [], 'delete' => []]]);
}
protected function configureDatagridFilters(DatagridMapper $filter): void
{
$filter->add('reference')->add('status')->add('createdAt');
}
}
Register with the tag attributes that drive the sidebar (group, label, manager_type, code/slug, pager_type). Tag names are the single most likely breakage point versus Sonata — grep the bundle's DependencyInjection/ for the tag string before guessing.
Layouts over inheritance. Use with()/end() blocks in the mappers to build the TailAdmin two-column form/list layout. This is where the fork actually earns its keep: the grid classes and default templates are Tailwind-native, so form groups map to Tailwind columns instead of Bootstrap. Don't fight it with custom CSS — override the templates.
Custom actions via the CRUD controller. Keep business logic in a service, expose it through a thin controller extending the bundle's CRUD base, and route to it from configureRoutes() plus a ListMapper action. This is the cleanest seam for "approve", "resend", "export selection" style operations.
Batch actions and exporters. Batch actions are declared on the admin and dispatched per-id; exporters implement the bundle's exporter interface with setExportFields()/getExportFields(). Practical pattern: give each admin a getExportFields() that mirrors the list view, so CSV output and screen output never drift.
Blocks for the dashboard. The block extension works like Sonata's: implement the block service interface, tag the service, reference it from the dashboard config with a position/class. Use these for "latest orders", stat counters, and alert panels. Keep them cheap — dashboards render every block on every page load; wrap slow ones in a cache pool.
Template overrides, not forks of forks. Symfony resolves overrides at templates/bundles/<BundleName>/.... Find the bundle name via bin/console debug:twig and mirror the vendor path. This is the correct extension point for Tailwind class tweaks (denser tables, different badge colors) and survives a composer update far better than editing vendor.
Integration tip — decouple the admin from your domain. Point admins at DTOs or read-model entities where the admin's form mapper would otherwise expose internal columns. The admin layer is a UI concern; treat the Doctrine entities it touches as a boundary, especially if you later swap this alpha-quality fork out.
If you must reach it from Laravel: run the Symfony app as a separate service with its own database connection (read replica, or a shared schema with the admin writing to a queue), authenticate via SSO/JWT, and never share a service container. Expect to maintain two deployment units forever — budget accordingly.
The conflict is declared, not advisory. If any installed bundle — or a transitive dependency like a CMS bundle — requires sonata-project/*, Composer will refuse to install or will resolve to an old, broken graph. Run composer why sonata-project/admin-bundle and composer why-not idct/adminata before you plan anything. This is the #1 reason evaluation stalls.
Everything is renamed, nothing is documented. Existing Sonata admin classes need the full mechanical migration: Sonata\AdminBundle\Admin\AbstractAdmin → IDCT\Adminata\..., tag sonata.admin → whatever the fork uses, config root sonata_admin → new key, route names, translation domains, and template paths. Do this with a search-and-replace pass plus the test suite, not by hand. Any tutorial you find online is Sonata and will be subtly wrong.
Tailwind v4 content scanning will bite you. Tailwind v4 does not scan vendor/ by default. Add an explicit source glob for the bundle's templates in your CSS entrypoint:
@import "tailwindcss";
@source "../../vendor/idct/adminata/**/*.twig";
Symptom of getting this wrong: layout skeleton appears, but spacing/colors/badges are missing. Also remember npm run build (and your CI step) must run after composer install — a fresh deploy that skips the asset build ships a broken admin.
NOASSERTION license. The score reports NOASSERTION, meaning the metadata doesn't declare a recognized SPDX license. Forked Sonata code normally carries MIT headers, but "normally" is not a legal review. If this ships to a client or a commercial product, get sign-off and preserve upstream copyright notices in the fork. Do not assume MIT because the parent project is.
Zero stars, zero dependents, one maintainer-shaped risk. No community means no security advisories routed to you. Mitigations: pin an exact version ("idct/adminata": "1.2.3", not ^1.0), commit composer.lock, subscribe to sonata-project advisories yourself and diff the fork against upstream when one drops, and — if you're serious — vendor the fork into your monorepo so you can patch it. A hard fork with no downstream users will not be patched promptly.
Debugging toolkit. bin/console debug:container --tag=<admin-tag> to verify your admin is registered with the right tag and attributes (a missing group means it silently disappears from the sidebar). bin/console debug:router | grep admin for path/prefix mismatches. bin/console debug:event-dispatcher when pre/post persist hooks don't fire. bin/console cache:clear after every service definition change — admin classes are cached aggressively and stale definitions produce confusing "service not found" errors.
Extension points, ranked by safety. (1) Decorate a service. (2) Override a template under templates/bundles/. (3) Subclass AbstractAdmin and hook prePersist()/preUpdate()/configureQuery() — these are stable, documented seams and where audit logging, soft-delete scoping, and multi-tenant row filtering belong. (4) Patch vendor directly — only if you've committed to vendoring the fork.
Multi-tenancy is on you. configureQuery() is the correct place to scope lists to a tenant, but the form's association widgets and the exporter will happily leak rows unless you scope them too. Test every one of: list, filter, export, autocomplete, and direct object edit by URL. A fork with no test suite of its own will not catch your mistakes here.
Budget a spike, not a sprint. One day: install, resolve conflicts, generate one admin, get assets building, confirm Tailwind renders. If that day doesn't end green, the fork's cost is not the install — it's the permanent maintenance of an undocumented, single-maintainer, Sonata-shaped dependency that you cannot get help with.
How can I help you explore Laravel packages today?