Installation:
composer require ascensodigital/perfil-bundle
Enable the bundle in config/bundles.php:
return [
// ...
AscensoDigital\PerfilBundle\AscensoDigitalPerfilBundle::class => ['all' => true],
];
Database Migrations:
Run migrations to create the required tables (e.g., perfil, perfil_navegacion, perfil_reporte):
php bin/console doctrine:migrations:diff
php bin/console doctrine:migrations:migrate
First Use Case:
Admin, User, Guest) in the database via Perfil entity.PerfilNavegacion entity.PerfilReporte.Example CRUD via CLI:
php bin/console make:entity PerfilNavegacion --fields="name:string,url:string,perfil:many-to-one"
php bin/console make:entity PerfilReporte --fields="name:string,type:string,perfil:many-to-one"
Profile-Based Navigation:
PerfilNavegacion entity to dynamically render menus in templates (e.g., Twig):
{% for item in perfil_navegacion_list %}
<a href="{{ item.url }}">{{ item.name }}</a>
{% endfor %}
$profile = $this->getUser()->getPerfil(); // Assuming User extends UserBundle's User
$navItems = $profile->getNavegacions(); // Via Doctrine relations
Report Access Control:
PerfilReporte to gate report endpoints:
public function generateReportAction(PerfilReporte $report)
{
$userProfile = $this->getUser()->getPerfil();
if (!$userProfile->hasReporte($report)) {
throw $this->createAccessDeniedException();
}
// Generate report logic...
}
EasyAdmin Integration:
use AscensoDigital\PerfilBundle\Entity\Perfil;
class PerfilCrudController extends EasyAdminCrudController
{
public function configureFields(string $pageName): iterable
{
return [
Field::new('name'),
Field::new('description')->onlyOnIndex(),
AssociationField::new('navegacions'),
AssociationField::new('reportes'),
];
}
}
Slug-Based Routing:
cocur/slugify for SEO-friendly profile URLs:
$profile = $this->getDoctrine()->getRepository(Perfil::class)->findOneBy(['slug' => $slug]);
UserBundle Sync:
Link UserBundle's User entity to Perfil via a many-to-one relation:
// src/Entity/User.php
/**
* @ORM\ManyToOne(targetEntity="AscensoDigital\PerfilBundle\Entity\Perfil")
*/
private $perfil;
Override loadUserByUsername to hydrate the profile:
public function loadUserByUsername($username)
{
$user = parent::loadUserByUsername($username);
$user->setPerfil($this->getDoctrine()->getRepository(Perfil::class)->findOneBy(['user' => $user]));
return $user;
}
Event Listeners: Trigger actions on profile changes (e.g., clear cache for navigation):
// src/EventListener/PerfilListener.php
class PerfilListener implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return [
KernelEvents::VIEW => ['onKernelView'],
];
}
public function onKernelView(GetResponseForControllerResultEvent $event)
{
$profile = $this->getUser()->getPerfil();
$event->getControllerResult()->setData(['nav_items' => $profile->getNavegacions()]);
}
}
Deprecated Dependencies:
easycorp/easyadmin-bundle:^3.4).friendsofsymfony/user-bundle).Missing Doctrine Relations:
Perfil, PerfilNavegacion, and PerfilReporte entities may lack proper Doctrine mappings in the source.Perfil entity:
/**
* @ORM\OneToMany(targetEntity="AscensoDigital\PerfilBundle\Entity\PerfilNavegacion", mappedBy="perfil")
*/
private $navegacions;
Hardcoded EasyAdmin Routes:
config/routes.yaml or use a feature flag.No Built-in ACL:
sonata-project/admin-bundle or symfony/security for fine-grained control.dump($this->getUser()->getPerfil()->getNavegacions()->map(fn($item) => $item->getUrl()));
doctrine/doctrine-fixtures-bundle. Load sample data with:
php bin/console doctrine:fixtures:load
Custom Report Types:
Extend PerfilReporte to support new report formats (e.g., CSV, Excel):
// src/Entity/CustomPerfilReporte.php
class CustomPerfilReporte extends PerfilReporte
{
private $format; // e.g., 'xlsx'
// Add getters/setters and override generate() logic.
}
Dynamic Navigation: Use Twig extensions to filter navigation items dynamically:
{% set activeNav = perfil_navegacion_list|filter((item) => item.url == app.request.uri) %}
Profile Inheritance:
Implement a ProfileHierarchy trait to allow profiles to inherit navigation/reports:
trait ProfileHierarchy
{
public function getAllNavegacions(): Collection
{
return $this->navegacions->merge($this->parent?->getAllNavegacions());
}
}
ascenso_digital_perfil as a default namespace prefix. Override in config/packages/ascenso_digital_perfil.yaml if needed.PerfilNavegacion labels in translations/messages.en.yaml:
navigation:
name: "Navigation Item"
$profile = $this->getDoctrine()
->getRepository(Perfil::class)
->find($id, ['navegacions' => 'join', 'reportes' => 'join']);
```markdown
---
How can I help you explore Laravel packages today?