danielpanzella/bitbucket-api-bundle
Install the Bundle:
composer require danielpanzella/bitbucket-api-bundle
Register the bundle in config/bundles.php:
return [
// ...
DanielPanzella\BitbucketApiBundle\DanielPanzellaBitbucketApiBundle::class => ['all' => true],
];
Configure OAuth2 Credentials:
Add your Bitbucket OAuth2 credentials to config/packages/bitbucket_api.yaml:
bitbucket_api:
client_id: '%env(BITBUCKET_CLIENT_ID)%'
client_secret: '%env(BITBUCKET_CLIENT_SECRET)%'
Store secrets in .env:
BITBUCKET_CLIENT_ID=your_client_id_here
BITBUCKET_CLIENT_SECRET=your_client_secret_here
First Use Case: Fetch User Profile Inject the API service and call a method:
use Bitbucket\API\Api;
public function __construct(Api $bitbucketApi)
{
$this->bitbucketApi = $bitbucketApi;
}
public function getUserProfile()
{
$user = $this->bitbucketApi->user()->get();
return $user->getUsername();
}
OAuth2 Flow: Redirect users to Bitbucket for authorization:
$authUrl = $this->bitbucketApi->getAuthorizationUrl(['scope' => 'repository']);
Handle the callback to exchange the code for an access token:
$token = $this->bitbucketApi->getAccessToken($code);
Storing Tokens:
Use Symfony’s security.token_storage or a custom service to persist tokens between requests.
Repositories:
$repos = $this->bitbucketApi->repository()->get();
foreach ($repos as $repo) {
$repoDetails = $this->bitbucketApi->repository()->get($repo->getSlug());
}
Pull Requests:
$prs = $this->bitbucketApi->pullrequest()->get('repo-slug');
$pr = $this->bitbucketApi->pullrequest()->get('repo-slug', $prId);
Commits:
$commits = $this->bitbucketApi->repository()->commits('repo-slug');
Use dependency injection to avoid manual service lookups:
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\HttpFoundation\Response;
class BitbucketController
{
#[Route('/bitbucket/user', name: 'bitbucket_user')]
public function userProfile(Api $bitbucketApi): Response
{
$user = $bitbucketApi->user()->get();
return new Response($user->getUsername());
}
}
Extend the bundle to handle token expiration:
use Bitbucket\API\Api;
use Symfony\Component\HttpKernel\Event\RequestEvent;
class BitbucketTokenListener
{
public function onKernelRequest(RequestEvent $event, Api $bitbucketApi)
{
if ($bitbucketApi->isTokenExpired()) {
$token = $bitbucketApi->refreshAccessToken();
// Store the new token
}
}
}
Deprecated Package:
The underlying bitbucket-api library (by gentlero) is outdated (last updated in 2017). Expect missing features or breaking changes if Bitbucket’s API evolves. Monitor for forks or alternatives like php-bitbucket-api.
Token Management: The bundle does not persist tokens by default. Implement a custom service to store and refresh tokens (e.g., using Doctrine or Symfony’s cache).
Rate Limiting:
Bitbucket’s API has rate limits. Handle 429 Too Many Requests responses gracefully:
try {
$response = $bitbucketApi->repository()->get('repo-slug');
} catch (\Bitbucket\API\Exception\ApiException $e) {
if ($e->getCode() === 429) {
sleep($e->getRetryAfter());
retry();
}
}
Symfony Version Compatibility:
The bundle assumes Symfony 3.3+ autowiring. For older versions, manually register the service in services.yaml:
services:
Bitbucket\API\Api:
arguments:
- '%bitbucket_api.client_id%'
- '%bitbucket_api.client_secret%'
Enable API Debugging:
Set the debug option in config to log requests/responses:
bitbucket_api:
debug: true
Inspect Raw Responses: Use a middleware to log API calls:
$this->bitbucketApi->getHttpClient()->getEventDispatcher()->addListener(
'request',
function (\Psr\Http\Message\RequestInterface $request) {
error_log($request->getUri());
}
);
Custom API Clients:
Extend the Api class to add domain-specific methods:
class CustomBitbucketApi extends \Bitbucket\API\Api
{
public function getRepoContributors(string $repoSlug): array
{
return $this->get("2.0/repositories/{$repoSlug}/contributors");
}
}
Override HTTP Client: Replace the default Guzzle client for custom behavior (e.g., retry logic):
bitbucket_api:
http_client: your_custom_client_service_id
Add New API Endpoints:
Use the bundle’s Api class to call undocumented endpoints:
$response = $this->bitbucketApi->get("2.0/repositories/{$slug}/custom-endpoint");
Missing Features: If a feature is missing (e.g., webhooks), use the raw HTTP client:
$response = $this->bitbucketApi->getHttpClient()->get("2.0/repositories/{$slug}/hooks");
Pagination:
Manually handle pagination for endpoints like /repositories/{workspace}/pull-requests:
$prs = [];
$page = 1;
do {
$prs = array_merge($prs, $this->bitbucketApi->pullrequest()->get('repo-slug', null, null, null, $page));
$page++;
} while (count($prs) >= $page * 10); // Adjust based on Bitbucket's page size
How can I help you explore Laravel packages today?