Installation:
composer require 21torr/rad
Add the bundle to config/bundles.php:
return [
// ...
RadBundle::class => ['all' => true],
];
First Use Case:
Use ApiResponse in a controller to standardize API responses:
use Rad\ApiResponse;
public function show(User $user): ApiResponse
{
return ApiResponse::ok($user);
}
Key Entry Points:
src/Rad/ namespace for core classes.ApiResponse as a builder for consistent API responses.// Controller
public function create(Request $request): ApiResponse
{
$data = $request->validate();
$user = User::create($data);
return ApiResponse::created($user, ['Location' => '/users/1']);
}
ApiResponseNormalizer::createResponse() for nested data normalization.EntityModel for CRUD operations with Doctrine.// Service
public function update(User $user, array $data): User
{
return EntityModel::update($user, $data, skipModified: true);
}
EntityModel::persist(): Unified add/edit.EntityModel::refresh(): Reload entity from DB.ImportData for robust data handling (e.g., CSV/JSON imports).$importData = ImportData::fromArray($rawData);
$normalized = $importData->normalize(['field' => fn($v) => strtolower($v)]);
null.AbilitiesVoter for attribute-based permissions.#[Can('edit', $user)]
public function edit(User $user): ApiResponse { ... }
AbilitiesVoter to add custom attributes (e.g., @Can('delete')).TranslationHelper for dynamic translations.$helper = new TranslationHelper($translator);
$message = $helper->translate('user.welcome', ['name' => $user->name]);
ArgumentBag for typed request data.$bag = new ArgumentBag($request->all());
$email = $bag->getString('email'); // Validates and casts
Rad\ApiResponse, Rad\EntityModel, etc.
public function __construct(
private EntityModel $entityModel,
private TranslationHelper $translator
) {}
DoctrineChangeChecker (deprecated in v3.4.5+) for pre-update validation:
$changes = DoctrineChangeChecker::getEntityChanges($entityManager, $user);
if ($changes->hasChanges()) {
$this->denyAccessUnlessGranted('edit', $user);
}
Rad\BaseController for shared logic:
class UserController extends BaseController
{
public function index(): ApiResponse
{
return $this->respondWith($this->userService->list());
}
}
ApiResponse::mock() for unit tests:
$mockResponse = ApiResponse::mock()->withData(['id' => 1]);
$this->assertEquals(200, $mockResponse->getStatusCode());
Deprecated Features:
DoctrineChangeChecker is deprecated (v3.4.5+). Use custom logic or AbilitiesVoter instead.Model class is removed (v3.0.0+). Use EntityModel or raw Doctrine.PHP Version:
Type Safety:
ArgumentBag throws exceptions for invalid types. Validate early:
$bag->assertHas('email', 'string');
Doctrine Quirks:
EntityModel::update() marks entities as modified by default. Use skipModified: true for bulk updates:
EntityModel::update($entity, $data, skipModified: true);
Translation Dependencies:
TranslationHelper requires symfony/translator. Install if missing:
composer require symfony/translator
API Responses:
$this->container->getParameter('kernel.debug') // Check for debug logs
Entity Changes:
DoctrineChangeChecker::getEntityChanges() (if not deprecated) to debug modified fields:
dd(DoctrineChangeChecker::getEntityChanges($entityManager, $entity));
ImportData:
$importData = ImportData::fromArray($rawData);
$importData->normalize(['field' => fn($v) => $v ?? null]); // Handle nulls
Custom Voters:
AbilitiesVoter to add custom attributes:
class CustomVoter extends AbilitiesVoter
{
protected function supports(string $attribute, $subject): bool
{
return in_array($attribute, ['custom:action']);
}
}
ApiResponse Decorators:
ApiResponse to add middleware (e.g., logging):
$response = ApiResponse::ok($data);
$response->withHeader('X-Custom', 'value');
EntityModel Hooks:
EntityModel methods for custom logic:
class CustomEntityModel extends EntityModel
{
public static function persist(object $entity, array $data): object
{
// Add pre-persist logic
return parent::persist($entity, $data);
}
}
Translation Catalogs:
TranslationHelper to support custom domains:
$helper = new TranslationHelper($translator, 'custom_domain');
Optional Dependencies:
symfony/translator is optional. Explicitly require it if using TranslationHelper.Cache Invalidation:
InMemoryCache is not persistent. Use for short-lived data only.Id Fields:
int for IDs (v3.2.1+). Adjust Doctrine mappings if needed:
# config/doctrine.yaml
orm:
mappings:
App:
type: attribute
dir: '%kernel.project_dir%/src/Entity'
prefix: 'App\Entity'
alias: App
is_bundle: false
# Ensure unsigned int for IDs
id_generator:
strategy: UUID # or custom strategy
Enum Support:
EnumValue helper for type-safe enums:
$enumValue = EnumValue::from(UserRole::ADMIN);
How can I help you explore Laravel packages today?