编程

使用 Stringable 属性简化 Laravel 模型

160 2024-11-28 19:49:00

Laravel 的 AsStringable cast是一个强大的工具,可以显著增强在 Eloquent 模型中使用字符串属性的方式。通过将字符串属性转换为 Stringable 对象,你可以访问各种字符串操作方法,从而生成更清晰、更具表现力的代码。

在模型中实现 AsStringable

要使用 AsStringable cast,只需在模型的 $casts 属性中指定它:

use Illuminate\Database\Eloquent\Casts\AsStringable;

class Post extends Model
{
    protected $casts = [
        'title' => AsStringable::class,
        'content' => AsStringable::class,
    ];
}

真实案例:博客帖子(Post)管理

让我们假定有一个博客应用,出于各种目的,我们需要操纵帖子标题和内容。以下是我们如何利用 Stringable 属性:

class Post extends Model
{
    protected $casts = [
        'title' => AsStringable::class,
        'content' => AsStringable::class,
    ];

    public function getSnippetAttribute()
    {
        return $this->content->words(20)->append('...');
    }

    public function getSlugAttribute()
    {
        return $this->title->slug();
    }

    public function getFormattedContentAttribute()
    {
        return $this->content
            ->replaceMatches('/\*\*(.*?)\*\*/', '<strong>$1</strong>')
            ->replaceMatches('/\*(.*?)\*/', '<em>$1</em>')
            ->replaceMatches('/\n/', '<br>');
    }
}

本例中:

• 我们将 titlecontent 都强制转换为 Stringable。
getSnippetAttribute() 创建了帖子内容的 20 字预览。
getSlugAttribute() 从帖子标题中生成一个对 URL 友好的 slug。
getFormattedContentAttribute() 将一些基础 Markdown 式格式应用到内容中。

控制器中的用例:

class PostController extends Controller
{
    public function show(Post $post)
    {
        return view('posts.show', [
            'post' => $post,
            'snippet' => $post->snippet,
            'formattedContent' => $post->formatted_content,
        ]);
    }

    public function index()
    {
        $posts = Post::all()->map(function ($post) {
            return [
                'id' => $post->id,
                'title' => $post->title->title(),
                'snippet' => $post->snippet,
                'slug' => $post->slug,
            ];
        });

        return view('posts.index', compact('posts'));
    }
}

在 Blade 模板中:

<!-- posts/show.blade.php -->
<h1>{{ $post->title->title() }}</h1>
<p class="snippet">{{ $snippet }}</p>
<div class="content">{!! $formattedContent !!}</div>

<!-- posts/index.blade.php -->
@foreach ($posts as $post)
    <article>
        <h2><a href="{{ route('posts.show', $post['slug']) }}">{{ $post['title'] }}</a></h2>
        <p>{{ $post['snippet'] }}</p>
    </article>
@endforeach

这种方法尤其对于博客、维基或文档系统等内容密集型应用特别有用。它允许在模型中封装常见的字符串操作,保持控制器和视图的整洁,并专注于它们的主要职责。