heymowski/latest-news-reader
Laravel package for reading latest news from RSS/Atom feeds using SimplePie. Add feed sources via Artisan command, migrate a DB table, then fetch and store feed items with a command to load all sources.
Installation
composer require heymowski/latest-news-reader
php artisan migrate
news_sources and news_items tables exist in your database.First Use Case: Adding a News Source
php artisan LNR-Sources:AddNewsSource
https://feeds.feedburner.com/TechCrunch)daily or hourly).Fetching News Items
php artisan LNR-Items:ReadAll
news_items table with parsed feed items (title, description, link, published date).database/news_items for results.Displaying News in a View Inject the service into a controller:
use Heymowski\LatestNewsReader\Facades\NewsReader;
public function showNews()
{
$items = NewsReader::getLatestItems(5); // Fetch 5 latest items
return view('news.index', compact('items'));
}
@foreach($items as $item)
<article>
<h3><a href="{{ $item->link }}">{{ $item->title }}</a></h3>
<p>{{ Str::limit($item->description, 100) }}</p>
<small>{{ $item->published_at->format('M d, Y') }}</small>
</article>
@endforeach
Scheduled Updates Use Laravel’s scheduler to auto-fetch feeds (e.g., daily):
// app/Console/Kernel.php
protected function schedule(Schedule $schedule)
{
$schedule->command('LNR-Items:ReadAll')->daily();
}
last_updated_at column to news_sources to avoid redundant fetches.Dynamic Source Management
use Heymowski\LatestNewsReader\Models\NewsSource;
$source = NewsSource::create([
'name' => 'BBC News',
'feed_url' => 'http://feeds.bbci.co.uk/news/rss.xml',
'frequency' => 'hourly',
]);
$source->updateFeed(); // Manually fetch items for a specific source
Filtering and Querying
$techNews = NewsReader::getItemsBySource('TechCrunch', 10);
$recentItems = NewsReader::getItems()->where('published_at', '>', now()->subDays(7))->get();
Caching for Performance
$items = Cache::remember('latest_news_items', now()->addHours(1), function () {
return NewsReader::getLatestItems(10);
});
Service Provider Binding:
Extend the package’s NewsReader facade to add custom logic:
// app/Providers/AppServiceProvider.php
public function boot()
{
\Heymowski\LatestNewsReader\Facades\NewsReader::extend(function ($app) {
return new class($app['news-reader']) {
public function getTrendingItems($limit = 5) {
// Custom logic (e.g., filter by engagement metrics)
}
};
});
}
Event Listeners: Listen for feed updates to trigger notifications:
// app/Providers/EventServiceProvider.php
protected $listen = [
\Heymowski\LatestNewsReader\Events\FeedUpdated::class => [
\App\Listeners\SendNewsletter::class,
],
];
API Endpoints: Expose news items via Laravel API:
Route::get('/api/news', function () {
return NewsReader::getLatestItems(20);
});
Feed Parsing Errors
<title> tags).NewsReader::getLatestItems() in a try-catch:
try {
$items = NewsReader::getLatestItems();
} catch (\Exception $e) {
Log::error("Feed parse error: " . $e->getMessage());
return back()->with('error', 'Failed to fetch news.');
}
storage/logs/laravel.log for SimplePie errors.Duplicate Items
guid column to news_items and use Laravel’s unique() rule:
// app/Models/NewsItem.php
protected $fillable = ['title', 'description', 'link', 'published_at', 'guid'];
protected $unique = ['guid'];
Rate Limiting
429 Too Many Requests).ReadAll command:
// app/Console/Commands/ReadAll.php
public function handle()
{
$attempts = 0;
while ($attempts < 3) {
try {
$this->fetchFeeds();
break;
} catch (\GuzzleHttp\Exception\RequestException $e) {
if ($e->getCode() === 429) {
sleep(2 ** $attempts); // Exponential backoff
$attempts++;
} else {
throw $e;
}
}
}
}
Timezone Mismatches
published_at may not align with your app’s timezone.NewsItem model:
// app/Models/NewsItem.php
protected $dates = ['published_at'];
protected $appends = ['formatted_date'];
public function getFormattedDateAttribute()
{
return $this->published_at->setTimezone('America/New_York')->format('M d, Y H:i');
}
Inspect Raw Feed Data: Dump the parsed feed object before saving:
$feed = NewsReader::parseFeed($source->feed_url);
dd($feed->get_items()); // Debug SimplePie items
Artisan Debugging: Use Tinker to test queries:
php artisan tinker
>>> \Heymowski\LatestNewsReader\Models\NewsSource::all();
>>> \Heymowski\LatestNewsReader\Models\NewsItem::latest()->take(5)->get();
Custom Fields
Extend the news_items table and model:
// Migration
Schema::table('news_items', function (Blueprint $table) {
$table->string('author')->nullable();
$table->string('image_url')->nullable();
});
// Model
public $fillable = ['title', 'description', 'link', 'published_at', 'guid', 'author', 'image_url'];
Override Parsing Logic
Bind a custom parser to the news-reader service:
// config/news-reader.php
'parser' => \App\Services\CustomFeedParser::class,
Implement Heymowski\LatestNewsReader\Contracts\FeedParser.
Webhooks for Updates Trigger external APIs when feeds update:
// app/Providers/EventServiceProvider.php
protected $listen = [
\Heymowski\LatestNewsReader\Events\FeedUpdated::class => [
\App\Listeners\DispatchWebhook::class,
],
];
Localization
Handle non-English feeds by adding a locale column and translating titles/descriptions:
use LaravelLocalization;
$translatedTitle = LaravelLocalization::trans($item->title, [], 'en');
How can I help you explore Laravel packages today?