Installation
Add the bundle to your composer.json:
composer require becklyn/facebook-bundle
Enable it in config/bundles.php:
Becklyn\FacebookBundle\BecklynFacebookBundle::class => ['all' => true],
Configuration
Define the Facebook app in config/services.yaml (or legacy YAML):
services:
Facebook\Facebook:
arguments:
- { app_id: '%env(FACEBOOK_APP_ID)%', app_secret: '%env(FACEBOOK_APP_SECRET)%', default_graph_version: 'v12.0' }
Becklyn\FacebookBundle\Model\FacebookAppModel:
arguments:
- '@Facebook\Facebook'
- '@session'
- '@router'
- 'https://www.facebook.com/your-page-url' # Fan page URL
- ['email', 'user_birthday'] # Required permissions
- 'default_session' # Session identifier
First Use Case
Inject FacebookAppModel into a controller and access user data:
use Becklyn\FacebookBundle\Model\FacebookAppModel;
class FacebookController extends AbstractController
{
public function index(FacebookAppModel $facebookApp): Response
{
$apiUser = $facebookApp->getApiUser();
$page = $facebookApp->getPage();
return $this->render('facebook/index.html.twig', [
'userEmail' => $apiUser->getEmail(),
'pageId' => $page->getId(),
]);
}
}
Authentication Flow Redirect users to Facebook for login:
$loginUrl = $facebookApp->getLoginUrl(['scope' => ['publish_stream']]);
return $this->redirect($loginUrl);
Handle the callback in a route:
public function callback(FacebookAppModel $facebookApp): Response
{
$facebookApp->handleCallback();
// User data is now available in session
return $this->redirect($this->generateUrl('home'));
}
Data Access Retrieve structured user/page data:
$requestUser = $facebookApp->getRequestUser(); // Signed request data (age, country, etc.)
$apiUser = $facebookApp->getApiUser(); // Full /me API data (email, name, etc.)
$page = $facebookApp->getPage(); // Page admin/ID from signed request
Session Persistence The bundle auto-persists data across iframe navigations. Access it anywhere:
$facebookApp->getSessionData(); // Raw session data
Permissions Handling Check if required permissions are granted:
if (!$facebookApp->hasPermission('email')) {
throw new \RuntimeException('Email permission required!');
}
Twig Integration
Pass FacebookAppModel to templates for dynamic content:
{% if facebookApp.getApiUser() %}
Welcome, {{ facebookApp.getApiUser().name }}!
{% endif %}
Event Listeners Subscribe to Facebook events (e.g., post-install):
# config/services.yaml
services:
App\EventListener\FacebookListener:
tags:
- { name: kernel.event_listener, event: facebook.post_install, method: onPostInstall }
Multi-App Support
Use unique session_identifier for multiple Facebook apps:
Becklyn\FacebookBundle\Model\FacebookAppModel.second_app:
arguments:
- '@Facebook\Facebook.second_app'
- '@session'
- '@router'
- 'https://www.facebook.com/another-page'
- ['email']
- 'second_app_session'
Deprecated Facebook SDK
The bundle uses the legacy facebook/graph-sdk (v5.x). Ensure compatibility with Facebook’s API by:
composer.json:
"facebook/graph-sdk": "5.7.0"
default_graph_version in your service config to match your needs (e.g., v12.0).Session Handling
session_identifier is unique. Overlapping sessions may corrupt data.session.storage.handler_id in .env if using custom storage (e.g., Redis):
SESSION_STORAGE=redis
Permissions Scope
getApiUser() returns null, verify:
scope parameter in getLoginUrl() matches the permissions defined in the service config.user_about_me) are deprecated. Replace with modern equivalents (e.g., email, public_profile).Signed Request Validation
getRequestUser() or getPage() returns null, check:
signed_request is being passed correctly in the iframe URL.app_id in the service config matches the app ID in Facebook Developer Dashboard.Archived Status
facebook/webdriver (for testing).spatie/laravel-facebook (Laravel-specific).Enable Debug Mode Temporarily enable Facebook SDK debug mode:
services:
Facebook\Facebook:
arguments:
- { app_id: '%env(FACEBOOK_APP_ID)%', app_secret: '%env(FACEBOOK_APP_SECRET)%', default_graph_version: 'v12.0', debug: true }
Check logs for errors like OAuthException.
Inspect Session Data Dump session data to verify persistence:
dump($facebookApp->getSessionData());
Validate Signed Request
Manually decode the signed_request to debug:
$signedRequest = $_REQUEST['signed_request'];
list($encodedSig, $payload) = explode('.', $signedRequest, 2);
$data = json_decode(base64_decode(strtr($payload, '-_', '+/')), true);
Custom Value Objects
Extend the bundled value objects (Page, RequestUser, ApiUser) for additional fields:
class CustomApiUser extends \Becklyn\FacebookBundle\Model\ApiUser
{
public function getCustomField()
{
return $this->data['custom_field'] ?? null;
}
}
Override the service definition to use your class.
Event Dispatching
Extend functionality by listening to internal events (e.g., facebook.post_install):
use Becklyn\FacebookBundle\Event\FacebookEvents;
public function onPostInstall(PostInstallEvent $event)
{
// Handle post-install logic (e.g., create user in your DB)
}
API Wrapper Create a service to wrap common API calls:
class FacebookApiService
{
public function __construct(private FacebookAppModel $facebookApp) {}
public function publishToWall(string $message): array
{
return $this->facebookApp->getFacebook()->post(
'/me/feed',
['message' => $message],
$this->facebookApp->getAccessToken()
);
}
}
Configuration Overrides Override default behavior via compiler passes or runtime configuration:
# config/packages/becklyn_facebook.yaml
becklyn_facebook:
required_permissions: ['email', 'public_profile'] # Override globally
session_identifier: 'custom_session'
How can I help you explore Laravel packages today?