jonnybarnes.uk/app/Models/Article.php
Jonny Barnes c420e19f08
Replace abandoned spatie/commonmark-highlighter with tempest/highlight
Swap the syntax highlighting library and its CSS theme (zenburn -> nord,
matching tempest's class names), add padding to code blocks, and commit
the missing compressed winter.js assets from the earlier asset rename.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-14 18:37:05 +01:00

120 lines
3.3 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Models;
use Cviebrock\EloquentSluggable\Sluggable;
use Illuminate\Database\Eloquent\Attributes\Fillable;
use Illuminate\Database\Eloquent\Attributes\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use League\CommonMark\Environment\Environment;
use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
use League\CommonMark\MarkdownConverter;
use Tempest\Highlight\CommonMark\HighlightExtension;
#[Table('articles')]
#[Fillable(['url', 'title', 'main', 'published'])]
class Article extends Model
{
use HasFactory;
use Sluggable;
use SoftDeletes;
/** @var array<string, string> */
protected $casts = [
'created_at' => 'datetime',
'updated_at' => 'datetime',
'deleted_at' => 'datetime',
];
/**
* Return the sluggable configuration array for this model.
*/
public function sluggable(): array
{
return [
'titleurl' => [
'source' => 'title',
],
];
}
protected function html(): Attribute
{
return Attribute::get(
get: function () {
$environment = new Environment;
$environment->addExtension(new CommonMarkCoreExtension);
$environment->addExtension(new HighlightExtension);
$markdownConverter = new MarkdownConverter($environment);
return $markdownConverter->convert($this->main)->getContent();
},
);
}
protected function w3cTime(): Attribute
{
return Attribute::get(
get: fn () => $this->updated_at->toW3CString(),
);
}
protected function tooltipTime(): Attribute
{
return Attribute::get(
get: fn () => $this->updated_at->toRFC850String(),
);
}
protected function humanTime(): Attribute
{
return Attribute::get(
get: fn () => $this->updated_at->diffForHumans(),
);
}
protected function pubdate(): Attribute
{
return Attribute::get(
get: fn () => $this->updated_at->toRSSString(),
);
}
protected function link(): Attribute
{
return Attribute::get(
get: fn () => '/blog/'.$this->updated_at->year.'/'.$this->updated_at->format('m').'/'.$this->titleurl,
);
}
/**
* Scope a query to only include articles from a particular year/month.
*/
public function scopeDate(Builder $query, ?int $year = null, ?int $month = null): Builder
{
if ($year === null) {
return $query;
}
$start = $year.'-01-01 00:00:00';
$end = ($year + 1).'-01-01 00:00:00';
if (($month !== null) && ($month !== 12)) {
$start = $year.'-'.$month.'-01 00:00:00';
$end = $year.'-'.($month + 1).'-01 00:00:00';
}
if ($month === 12) {
$start = $year.'-12-01 00:00:00';
$end = ($year + 1).'-01-01 00:00:00';
}
return $query->where([
['updated_at', '>=', $start],
['updated_at', '<', $end],
]);
}
}