dbp/relay-portfolio-bundle
DbpRelayPortfolioBundle provides a relay bundle for integrating portfolio-related features into DBP applications. Use it to connect, expose, and manage portfolio data through a standardized bundle structure within your Symfony/DBP setup.
Installation Add the bundle via Composer:
composer require dbp/relay-portfolio-bundle
Enable it in config/bundles.php:
return [
// ...
DigitalBlueprint\RelayPortfolioBundle\RelayPortfolioBundle::class => ['all' => true],
];
Publish Configuration Run:
php bin/console dbp:relay-portfolio:install
This generates:
database/migrations/...)config/packages/relay_portfolio.yaml)First Use Case: Basic Portfolio Entry Create a portfolio entry via CLI:
php bin/console dbp:relay-portfolio:create
Follow prompts to define a project (title, description, tags, etc.). Verify in database or via:
php bin/console dbp:relay-portfolio:list
Key Configuration
Review config/packages/relay_portfolio.yaml for:
default_locale (e.g., en)storage (local filesystem or S3 for assets)routing (prefix, e.g., /portfolio).CRUD via CLI
dbp:relay-portfolio:create (interactive or JSON input).
Example JSON input:
php bin/console dbp:relay-portfolio:create --json '{"title": "Laravel App", "description": "A SaaS platform", "tags": ["laravel", "sass"]}'
dbp:relay-portfolio:edit <id> (interactive or JSON).dbp:relay-portfolio:delete <id>.dbp:relay-portfolio:list (filter by tags/date).Asset Management Upload assets (images, PDFs) via:
php bin/console dbp:relay-portfolio:upload <id> <path/to/file>
Configure storage in relay_portfolio.yaml:
storage:
driver: 'local' # or 's3'
path: '%kernel.project_dir%/public/uploads/portfolio'
s3:
bucket: 'my-bucket'
key: 'my-key'
API Endpoints
The bundle auto-generates API routes under /api/portfolio:
GET /api/portfolio (list with pagination).GET /api/portfolio/{id} (single entry).POST/PUT/DELETE for CRUD (authenticated via ROLE_PORTFOLIO_EDITOR).Twig Integration Access portfolio entries in templates:
{% for project in app.service('relay_portfolio.manager').findAll() %}
<h2>{{ project.title }}</h2>
<img src="{{ asset(project.coverImageUrl) }}" alt="{{ project.title }}">
{% endfor %}
Event-Driven Extensions
Listen to portfolio events (e.g., PortfolioEntryCreated) in EventSubscribers:
namespace App\EventListener;
use DigitalBlueprint\RelayPortfolioBundle\Event\PortfolioEntryEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class PortfolioNotifier implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return [
PortfolioEntryEvent::CREATED => 'onPortfolioCreated',
];
}
public function onPortfolioCreated(PortfolioEntryEvent $event)
{
// Send notification (e.g., Slack, email)
}
}
Authentication
Secure API routes by adding guards to security.yaml:
access_control:
- { path: ^/api/portfolio, roles: ROLE_PORTFOLIO_EDITOR }
Create a custom role in security.yaml:
role_hierarchy:
ROLE_PORTFOLIO_EDITOR: [ROLE_USER]
Custom Fields
Extend the PortfolioEntry entity by creating a custom field type:
// src/Entity/PortfolioExtension.php
namespace App\Entity;
use DigitalBlueprint\RelayPortfolioBundle\Entity\PortfolioEntry;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity]
class PortfolioExtension
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
#[ORM\OneToOne(targetEntity: PortfolioEntry::class, inversedBy: 'extension')]
private PortfolioEntry $portfolioEntry;
#[ORM\Column(type: 'json')]
private array $customData = [];
// Getters/setters...
}
Register the extension in the bundle’s configuration.
Testing
Use the bundle’s test utilities in PHPUnit:
use DigitalBlueprint\RelayPortfolioBundle\Tests\PortfolioTestCase;
class MyPortfolioTest extends PortfolioTestCase
{
public function testCreatePortfolioEntry()
{
$entry = $this->createPortfolioEntry(['title' => 'Test']);
$this->assertEquals('Test', $entry->getTitle());
}
}
Migration Conflicts
PortfolioEntry entity after initial setup, drop and recreate migrations:
php bin/console doctrine:migrations:diff
php bin/console doctrine:migrations:migrate
Storage Permissions
storage path in relay_portfolio.yaml is writable:
chmod -R 775 %kernel.project_dir%/public/uploads/portfolio
Locale Handling
en. To add multilingual support:
# config/packages/relay_portfolio.yaml
locales: [en, fr]
trans() in Twig:
{{ 'portfolio.label.title'|trans }}
Event Dispatching
services.yaml:
DigitalBlueprint\RelayPortfolioBundle\:
resource: '../vendor/digital-blueprint/relay-portfolio-bundle/src/'
exclude: '../vendor/digital-blueprint/relay-portfolio-bundle/src/{Entity,Tests,DependencyInjection/Configuration.php}'
API Rate Limiting
config/packages/security.yaml:
firewalls:
main:
rate_limiting:
api_portfolio:
path: ^/api/portfolio
limit: 60
Log Entries
Enable debug logging in config/packages/monolog.yaml:
handlers:
main:
type: stream
path: "%kernel.logs_dir%/%kernel.environment%.log"
level: debug
channels: ["!event"]
Filter for relay_portfolio:
grep -i "relay_portfolio" %kernel.logs_dir%/dev.log
Doctrine Debugging Dump portfolio entries:
use Doctrine\ORM\EntityManagerInterface;
class DebugController
{
public function __construct(private EntityManagerInterface $em) {}
public function dumpPortfolio()
{
$entries = $this->em->getRepository(DigitalBlueprint\RelayPortfolioBundle\Entity\PortfolioEntry::class)->findAll();
dd($entries);
}
}
CLI Verbosity Increase CLI output for commands:
php bin/console dbp:relay-portfolio:create -v
Custom Validators Add validation to portfolio entries by creating a custom constraint:
namespace App\Validator;
use Symfony\Component\Validator\Constraint;
#[Attribute]
class UniqueTag
{
public string $message = 'This tag already exists.';
}
Register it in services.yaml:
App\Validator\UniqueTagValidator: ~
Custom Templates Override Twig templates by copying them from:
vendor/digital-blueprint/relay-portfolio-bundle/src/Resources/views/
to:
templates/bundles/relayportfolio/
**Graph
How can I help you explore Laravel packages today?