Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Bitly Bundle Laravel Package

hpatoio/bitly-bundle

Symfony bundle that integrates the Bitly API for URL shortening and link management. Provides service configuration to generate short links from controllers or templates. Small, low-activity package; verify maintenance and API compatibility before use.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and register

composer require hpatoio/bitly-bundle:^1.0.5

Pin the constraint explicitly. The bundle predates Flex, so there is almost certainly no recipe. Register it manually:

// Symfony 4+: config/bundles.php
Hpatoio\BitlyBundle\HpatoioBitlyBundle::class => ['all' => true],

// Symfony 2/3: app/AppKernel.php
new Hpatoio\BitlyBundle\HpatoioBitlyBundle(),

Configure the token

The 1.0.5 release exists solely to fix the bundle's YAML format for Symfony 4 (See #6). That means the Symfony 4 config file format is now the supported one — write it under config/packages/:

# config/packages/hpatoio_bitly.yaml
hpatoio_bitly:
    access_token: '%env(BITLY_ACCESS_TOKEN)%'

If you are maintaining a Symfony 2/3 app, the pre-1.0.5 YAML shape is what you get from older tags; upgrade or hand-write the equivalent. Either way, don't guess the key names — dump them:

bin/console config:dump-reference hpatoio_bitly

If %env()% fails to resolve at compile time, that is the bundle's extension not being env-aware (the YAML fix did not touch the PHP Configuration/Extension classes). Bind it as a parameter instead:

# config/services.yaml
parameters:
    bitly_access_token: '%env(BITLY_ACCESS_TOKEN)%'

Find the service before writing code

bin/console debug:container bitly --show-private
bin/console debug:container --tag=data_collector | grep -i bitly

The bundle registers a client service (something like hpatoio_bitly.api or bitly.api) that is a thin wrapper around hpatoio/bitly-api, decorated with a logging layer. Grab the real ID from the command above; the exact ID has varied across versions and the 1.0.5 patch did not add autowiring aliases.

First use case: shorten a URL

// src/Controller/ShareController.php
public function share(string $url): Response
{
    $short = $this->get('hpatoio_bitly.api')->shorten($url);

    return $this->json(['short' => (string) $short]);
}

Verify the return shape (plain string vs. object vs. array) against the hpatoio/bitly-api README for the pinned version — the client returns raw-ish decoded responses and this is the number one source of "works in my head, not in prod" bugs. The 1.0.5 release changed configuration YAML only; it did not touch the client or its response handling.

Then open any page in dev and check the web profiler toolbar for a Bitly panel. That panel is the fastest sanity check that the token, HTTP client, and logging decorator are all wired correctly.

Implementation Patterns

Wrap the client in your own service. Never inject the bundle's client directly into controllers. A single ShortLinkManager gives you one place to handle caching, retries, error degradation, and tests.

// src/ShortLink/ShortLinkManager.php
final class ShortLinkManager
{
    public function __construct(
        private object $bitly,                 // the bundle service
        private CacheItemPoolInterface $cache,
        private LoggerInterface $logger,
    ) {}

    public function shorten(string $url): ?string
    {
        try {
            $key = 'bitly.shorten.'.hash('xxh3', $url);
            return $this->cache->get($key, function (ItemInterface $item) use ($url) {
                $item->expiresAfter(86400 * 30);
                return (string) $this->bitly->shorten($url);
            });
        } catch (\Throwable $e) {
            $this->logger->warning('Bitly shorten failed', ['url' => $url, 'e' => $e]);
            return null; // caller falls back to the full URL
        }
    }
}

Autowire via an alias. Old bundles register private services with no alias, and 1.0.5 did not change that. Add one in config/services.yaml:

services:
    hpatoio_bitly.api: '@Hpatoio\Bitly\Client'   # or whatever debug:container shows

Then type-hint the client class (or your own interface) instead of using $this->get().

Persist the back-half / bitlink ID, not just the short URL. Bitly analytics endpoints need the link identifier, not the shortened string. If you plan to pull clicks/referrers later, store both:

$entity->setShortUrl($short);          // "http://bit.ly/2xY..."
$entity->setBitlyId($idFromResponse);  // needed for clicks(), countries(), referrers()

Resolving the ID after the fact means an extra expand/lookup round trip per record — do it at write time.

Cache aggressively on the read path. Expanding an inbound short link on every request is a latency tax and a rate-limit hazard. Short link → long link is immutable in practice; cache it forever (or a year).

Move writes off the request thread. Shortening inside a web request couples your page load to Bitly's availability and to your token's rate budget. If you generate links in bulk (campaigns, invites, imports), dispatch a Messenger job and write the result back to the entity.

Use it for a Twig helper if sharing is a UI concern:

{{ bitly_shorten(app.request.uri) ?? app.request.uri }}

Register the Twig function in your own extension that delegates to ShortLinkManager, not to the bundle client directly.

Analytics sync as a console command. The bundle adds nothing for scheduling; you own it.

// src/Command/SyncBitlyStatsCommand.php
foreach ($repo->findLinksNeedingStats() as $link) {
    $stats = $this->bitly->clicks($link->getBitlyId(), 'month'); // verify signature
    $repo->updateStats($link, $stats);
    usleep(100_000); // be polite; rate limits are real
}

Profiler as a debugging workflow. In dev, the data collector gives you the request URL, response, timing, and status per Bitly call. Use it to spot:

  • the same URL shortened multiple times in one page render (cache miss),
  • 403s (bad/expired token) that your try/catch swallowed,
  • slow calls (>500ms) that should move to async.

Gotchas and Tips

  • Age is still the biggest risk, but the bundle is not fully dead. 1.0.5 landed after a long dormancy and is a one-line scope change: YAML format compatibility for Symfony 4. No client changes, no HTTP-layer changes, no new config options, no autowiring aliases. Treat the operational surface — everything below — as unchanged from the 2017-era code. Expect Symfony 2.8/3.x idioms: no aliases, no AbstractBundle, and a Configuration tree that may not resolve %env()% at compile time even though the YAML file itself is now SF4-valid.
  • Don't over-read the release. 1.0.5 is a compatibility patch, not a maintenance commitment. There is no changelog trail for the HTTP client, Guzzle constraint, or the profiler template. Keep composer.lock and review diffs before any bump beyond 1.0.5.
  • Verify the API version the client targets. The 2017 vintage straddles Bitly v3 (access_token + login) and early v4 (OAuth bearer), and 1.0.5 did not move that line. Sending a v4 token to v3 endpoints returns confusing auth errors, not a clean 401. Test one shorten by hand with curl before blaming the bundle.
  • Private services break $this->get(). On Symfony 4+, the client may not be publicly accessible from the container. Either add the alias above or inject it properly — don't fight the container.
  • The logging decorator can log secrets. If it dumps full request URLs at debug level, access_token query parameters end up in var/log/dev.log and, worse, in production if you raise the log level. Check the decorator's output format and scrub/redact before enabling in prod.
  • Nothing here throttles. Logging ≠ rate limiting. Bitly enforces per-token hourly limits and returns 429s. Implement retry-with-backoff (RetryableHttpClient or stop()/retry() on your own decorator) and a token-bucket if you're doing bulk work.
  • No retry, no circuit breaker out of the box. A Bitly outage will surface as an exception in your controller. Always degrade: return the original URL, queue the shorten, or hide the share button. Never let a marketing feature 500 your checkout page.
  • Mock the client in tests. Because you own ShortLinkManager, tests use a stub. For integration tests, swap the client service with a fake via services_test.yaml — the bundle's client is not final and can be decorated.
  • Pin the version. With no dependents and no recent releases beyond a YAML fix, there is no community pressure to keep it compatible with newer Guzzle/Symfony HTTP clients. composer.lock is your friend; a composer update can silently break a transitive Guzzle major.
  • Extension points, in order of usefulness: (1) decorate/replace the client service with your own implementation of the same interface, (2) wrap ShortLinkManager around it and never touch the client again, (3) add your own data collector only if the shipped one is too coarse — it's tied to old profiler template APIs and is the least portable part of the bundle.
  • Have a migration plan. If Bitly is core to your product, budget for replacing this bundle with a 100-line Guzzle wrapper against the v4 API. You'll lose the profiler panel and gain a dependency you can actually patch. The 1.0.5 YAML fix is a good excuse to schedule that review, not a reason to defer it.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin