yosimitso/workingforumbundle
WorkingForumBundle is a ready-to-use forum bundle for Symfony applications. It lets you add categories, topics, posts, moderation, pagination, BBCode formatting, and user-friendly discussion features to your site without building forum infrastructure from scratch.
v6.0 drops the long-abandoned sensio/framework-extra-bundle and shifts the package onto native Symfony attributes/argument resolvers. If you are consuming this from a Laravel app, the practical impact is: annotation-driven controllers no longer work, and the auth/route-model plumbing now runs through the container rather than a bundle extension.
composer require <vendor>/<package>:^6.0 --with-all-dependencies — the -W flag matters here because the release also pins several transitive symfony/* constraints that Laravel already pulls in.@Security → #[IsGranted], and ParamConverter → ArgumentResolver.config/<package>.php) still loads — v6 no longer merges defaults through the bundle's Extension class.@Security("is_granted(...)") docblock. Swap it for #[IsGranted('ROLE_ADMIN')] on the method and confirm the authorization checker is bound (see below).The first thing to verify after install is that your AppServiceProvider (or the package's provider) binds the package's AuthorizationCheckerInterface — the IsGranted attribute resolves it lazily and fails at request time, not boot time, if missing.
Attribute-first controllers. Move all docblock annotations to PHP 8 attributes. IsGranted accepts attribute, subject, message, and statusCode:
#[IsGranted(attribute: 'update', subject: 'post', statusCode: 403)]
public function update(Post $post) { /* ... */ }
Bind the package's checker to Laravel's Gate so attribute/subject map onto Gate::allows($ability, $model) — that keeps policies in one place instead of duplicating role strings.
Argument resolvers replace ParamConverters. v6 introduced the ValueResolverInterface contract. Register one resolver per type instead of one converter per route:
final class PostResolver implements ValueResolverInterface
{
public function resolve(Request $request, ArgumentMetadata $argument): iterable
{
return $argument->getType() === Post::class
? [Post::findOrFail($request->route('id'))]
: [];
}
}
Tag it (or register it in the provider) and give it a priority so it runs before the default RequestAttributeValueResolver for scalar id params.
Incremental migration workflow. Do this in a branch, in this order: (1) grep for @Security, @ParamConverter, @Route; (2) convert annotations to attributes mechanically; (3) delete any sensio/framework-extra-bundle config and the bundle registration; (4) run the full suite with the container cache cleared. Do not convert resolvers and attributes in the same commit — the failure modes look identical and are hard to untangle.
Pin the rendering libraries deliberately. The release raises minimums for both markdown rendering and time rendering. If you have your own pinned markdown renderer (e.g. league/commonmark) or time formatter, align your constraints in the same PR and assert output in tests — these libraries change whitespace and timezone defaults between minors.
framework-extra-bundle gone, leftover @Security docblocks are simply ignored. Your routes stay public and your tests stay green. Explicitly assert a 403 on a protected route after migrating.is_granted() no longer exists in expressions. If you kept any expression strings, #[IsGranted('is_granted("ROLE_ADMIN")')] will now be evaluated as a literal attribute name. Use plain attribute names ('ROLE_ADMIN') or the expression-language functions the package registers.subject: names a route parameter that is missing or a route-model binding that didn't fire, you get a NotFoundHttpException from the resolver rather than a clean 403. Order your resolvers so binding happens first.{id} → entity conversion. The old ParamConverter inferred the entity from the route parameter name. The new resolvers infer from the type hint. Untyped or mixed controller arguments silently receive the raw string.composer why-not symfony/http-kernel 6.x and prefer bumping laravel/framework over adding conflict blocks.php artisan optimize:clear is mandatory before debugging "my attribute isn't running" — the stale compiled container will happily serve v5 behaviour.AuthorizationCheckerInterface binding, the resolver tag name (renamed in v6), and the ArgumentMetadata API. Wrap custom resolvers behind your own interface if you support multiple package majors.php artisan route:list -v to confirm attribute routes registered; container lint (bin/console lint:container equivalent / php artisan about) to catch missing checker bindings; log inside resolve() when a resolver silently returns [].How can I help you explore Laravel packages today?