dev-master):
composer require astina/deadlink-bundle:1.2.1
config/bundles.php (Symfony 4+) or AppKernel.php (Symfony 2/3):
return [
// ...
Astina\Bundle\DeadlinkBundle\AstinaDeadlinkBundle::class => ['all' => true],
];
php bin/console astina:deadlink:check
Verify the command executes without errors and logs output (if LoggingListener is configured).DoctrineLinkSource in config/services.yaml:
services:
App\Deadlink\MyEntityLinkSource:
class: Astina\Bundle\DeadlinkBundle\Doctrine\DoctrineLinkSource
arguments:
- '@doctrine'
- 'App\Entity\Post' # Your entity class
- ['content', 'metaDescription'] # Fields containing URLs
- [] # Optional: Criteria to filter entities (e.g., `{'published': true}`)
tags:
- { name: astina_deadlink.link_source }
php bin/console astina:deadlink:check
Broken links in Post entities will trigger the astina_deadlink.broken_links event.Define Link Sources:
LinkSourceInterface for custom sources (e.g., scraping HTML, checking API responses).CmsPageLinkSource to validate links in a CMS.class CmsPageLinkSource implements LinkSourceInterface {
public function getLinks() {
// Fetch links from your CMS (e.g., database, API).
return ['https://example.com/page1', 'https://example.com/page2'];
}
}
tags:
- { name: astina_deadlink.link_source }
Handle Broken Links:
astina_deadlink.broken_links:
class DeadlinkNotifier {
public function onBrokenLinks(BrokenLinksEvent $event) {
$brokenLinks = $event->getBrokenLinks();
// Send email, update database, etc.
}
}
services:
App\Deadlink\DeadlinkNotifier:
tags:
- { name: kernel.event_listener, event: astina_deadlink.broken_links, method: onBrokenLinks }
Schedule Checks:
CronBundle or a CI/CD pipeline to run astina:deadlink:check periodically (e.g., nightly).Doctrine Integration:
DoctrineLinkSource for entities with URL fields. Filter entities with DQL criteria:
arguments:
- '@doctrine'
- 'App\Entity\Product'
- ['url', 'thumbnail']
- [{ 'active': true }] # Only check active products
Custom Link Extraction:
getLinks() to parse URLs from non-Doctrine sources (e.g., files, APIs):
public function getLinks() {
$html = file_get_contents('https://example.com');
preg_match_all('/https?://[^\s]+/i', $html, $matches);
return $matches[0];
}
Logging Configuration:
config/packages/monolog.yaml:
handlers:
deadlink:
type: stream
path: "%kernel.logs_dir%/deadlinks.log"
level: critical # or error, warning
LoggingListener is enabled (see README).Testing:
LinkSourceInterface in PHPUnit to test event listeners:
$linkSource = $this->createMock(LinkSourceInterface::class);
$linkSource->method('getLinks')->willReturn(['http://broken-link.test']);
$container->set('my_link_source', $linkSource);
Outdated Dependencies:
~2.0). For Symfony 4/5/6, consider forking or using alternatives like spatie/laravel-sitemap (Laravel) or symfony/panther for modern scraping.Event Dispatching Issues:
BrokenLinksEvent isn’t triggered, verify:
astina_deadlink.link_source tag is correctly applied to your service.LinkSourceInterface implementation returns valid URLs (no empty strings or malformed links).DeadlinkFinder service is autowired (it’s registered automatically by the bundle).Performance:
// In your LinkSourceInterface implementation
public function getLinks() {
$em = $this->doctrine->getManager();
$query = $em->createQuery('SELECT e FROM App\Entity\Post e WHERE e.published = :published')
->setParameter('published', true)
->setMaxResults(100); // Limit per batch
// ...
}
HTTP Client Limitations:
HttpClient (if available). For complex checks (e.g., redirects, auth), extend DeadlinkFinder or use a custom LinkValidatorInterface.Check Command Output:
-v for verbose mode:
php bin/console astina:deadlink:check -v
var/log/dev.log (Symfony 2/3) or var/log/debug.log (Symfony 4+).Validate URLs Manually:
curl or Postman to confirm they’re truly broken before debugging the bundle.Service Dumping:
php bin/console debug:container | grep -i deadlink
Custom Link Validators:
Astina\Bundle\DeadlinkBundle\Link\LinkValidatorInterface to add logic (e.g., check HTTP status codes, headers):
class CustomValidator implements LinkValidatorInterface {
public function isBroken($url) {
$response = file_get_contents($url);
return $response === false;
}
}
DeadlinkFinder service via dependency injection.Async Processing:
use Symfony\Component\Messenger\MessageBusInterface;
class AsyncDeadlinkListener {
public function __construct(private MessageBusInterface $bus) {}
public function onBrokenLinks(BrokenLinksEvent $event) {
$this->bus->dispatch(new BrokenLinkMessage($event->getBrokenLinks()));
}
}
GUI Dashboard:
BrokenLinksEvent data:
{% for link in app.container.get('event_dispatcher').getListeners('astina_deadlink.broken_links')[0].getBrokenLinks() %}
<li>{{ link.url }} (Status: {{ link.status }})</li>
{% endfor %}
Service Overrides:
DeadlinkFinder or LoggingListener in config/services.yaml:
services:
Astina\Bundle\DeadlinkBundle\Event\LoggingListener:
arguments:
- '@logger'
- 'error' # Change log level
Environment-Specific Checks:
config/packages/dev/astina_deadlink.yaml:
astina_deadlink:
enabled: false # Skip in dev environment
Doctrine Criteria:
arguments:
- '@doctrine'
- 'App\Entity\Article'
- ['body']
- [{ 'datePublished': { '>=': '2023-01-01' } }] # Only recent
How can I help you explore Laravel packages today?