PHP code example of giorgigrdzelidze / laravel-stringer
1. Go to this page and download the library: Download giorgigrdzelidze/laravel-stringer library . Choose the download type require .
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
giorgigrdzelidze / laravel-stringer example snippets
// 3. Bind two adapters in any service provider
$this->app->bind(\Stringer\Laravel\Contracts\ContentTarget::class, ArticleTarget::class);
$this->app->bind(\Stringer\Laravel\Contracts\ContextBuilder::class, PublicContextBuilder::class);
// 4. Register the Filament plugin
->plugin(\Stringer\Laravel\Filament\StringerPlugin::make())
// app/Models/Article.php
public function registerMediaConversions(?Media $media = null): void
{
$this->addMediaConversion('og')->fit(Fit::Crop, 1200, 630)->performOnCollections('cover');
$this->addMediaConversion('twitter')->fit(Fit::Crop, 1200, 675)->performOnCollections('cover');
$this->addMediaConversion('thumb')->fit(Fit::Crop, 400, 225)->performOnCollections('cover');
}
$article->getFirstMediaUrl('cover'); // 1792x1024 master
$article->getFirstMediaUrl('cover', 'og'); // 1200x630
$article->getFirstMediaUrl('cover', 'twitter'); // 1200x675
$article->getFirstMediaUrl('cover', 'thumb'); // 400x225
// app/Providers/Filament/AdminPanelProvider.php
use Stringer\Laravel\Filament\StringerPlugin;
public function panel(Panel $panel): Panel
{
return $panel
// ...
->plugin(StringerPlugin::make());
}
// app/Stringer/Adapters/ArticleTarget.php
use App\Models\Article;
use App\Models\ArticleCategory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
use Spatie\Tags\Tag;
use Stringer\Laravel\Contracts\ContentTarget;
use Stringer\Laravel\DataObjects\LocalizedDraft;
use Stringer\Laravel\Enums\FieldType;
use Stringer\Laravel\Models\BlogTopic;
use Stringer\Laravel\Models\StringerContentField;
final class ArticleTarget implements ContentTarget
{
public function __construct(
private readonly Article $articles,
private readonly ArticleCategory $categories,
) {}
public function write(LocalizedDraft $draft, ?BlogTopic $topic = null): Article
{
$article = $this->articles->newInstance();
$fields = StringerContentField::query()->where('is_active', true)->get()->keyBy('name');
$pendingTags = [];
foreach ($draft->fields as $name => $value) {
$field = $fields->get($name);
if (! $field) { continue; }
match ($field->type) {
FieldType::TranslatableString => $article->setTranslations($name, is_array($value) ? $value : []),
FieldType::TranslatableMarkdown => $article->setTranslations(
$name,
is_array($value) ? array_map(fn ($v) => is_string($v) ? (string) Str::markdown($v) : $v, $value) : [],
),
FieldType::Markdown => $article->{$name} = is_string($value) ? (string) Str::markdown($value) : $value,
FieldType::TagList => $pendingTags[$name] = $value,
FieldType::Category => $this->assignCategory($article, $value),
FieldType::Integer => $article->{$name} = (int) $value,
default => $article->{$name} = $value,
};
}
// G1: per-topic auto-publish opt-in. Default writes a draft.
$article->status = $topic?->target_status ?? 'draft';
$article->publish_at = ($topic && $topic->auto_publish) ? now() : null;
$article->save();
foreach ($pendingTags as $tagValue) { $this->syncTags($article, $tagValue); }
return $article;
}
public function editUrl(Model $record): string
{
return \App\Filament\Resources\ArticleResource::getUrl('edit', ['record' => $record]);
}
public function attachCover(Model $record, \Stringer\Laravel\DataObjects\GeneratedImage $image): void
{
if (! $record instanceof Article) {
return;
}
$record
->addMediaFromString($image->bytes)
->usingFileName('cover-'.$record->getKey().'.'.$image->extension())
->withCustomProperties([
'generator' => $image->sourceDriver,
'prompt' => $image->prompt,
'attribution' => $image->attribution,
])
->toMediaCollection('cover');
}
}
// app/Stringer/Adapters/PublicContextBuilder.php
use App\Models\{Article, ArticleCategory, Project, Repository};
use Stringer\Laravel\Contracts\ContextBuilder;
final class PublicContextBuilder implements ContextBuilder
{
public function __construct(
private readonly Article $articles,
private readonly Project $projects,
private readonly Repository $repositories,
private readonly ArticleCategory $categories,
) {}
public function build(): array
{
return [
'articles' => /* recent published articles, projected to {title, excerpt} */,
'projects' => /* recent visible projects */,
'repositories' => /* recent visible repositories */,
'categories' => /* all categories, projected to {name, slug, description} */,
];
}
}
$this->app->bind(\Stringer\Laravel\Contracts\ContentTarget::class, ArticleTarget::class);
$this->app->bind(\Stringer\Laravel\Contracts\ContextBuilder::class, PublicContextBuilder::class);
bash
# 1. Install
composer rtisan db:seed --class="Stringer\Laravel\Database\Seeders\StringerDefaultPromptsSeeder"
php artisan db:seed --class="Stringer\Laravel\Database\Seeders\StringerDefaultContentFieldsSeeder"
bash
# 5. Trigger your first draft
php artisan queue:work &
php artisan tinker --execute="\$t = app(Stringer\Laravel\Services\TopicQueue::class)->enqueue('write about laravel queue retries', Stringer\Laravel\Enums\TopicSource::Manual); Stringer\Laravel\Jobs\GenerateDraftJob::dispatch(\$t->id);"
bash
php artisan db:seed --class="Stringer\Laravel\Database\Seeders\StringerDefaultPromptsSeeder"
php artisan db:seed --class="Stringer\Laravel\Database\Seeders\StringerDefaultContentFieldsSeeder"
bash
php artisan stringer:images:backfill # everything eligible
php artisan stringer:images:backfill --driver=unsplash # one-off driver override
php artisan stringer:images:backfill --limit=10 # cap the batch
php artisan stringer:images:backfill --sync # run inline, no queue