esign/laravel-linkable

动态链接 Laravel 模型

1.2.0 2024-03-12 22:48 UTC

This package is auto-updated.

Last update: 2024-09-12 23:56:46 UTC


README

Latest Version on Packagist Total Downloads GitHub Actions

此包允许您向 Laravel 模型添加动态链接。此动态链接可以指向另一个模型或外部 URL。本质上,这个包只是一个具有额外实用方法的 Laravel 关系。

安装

您可以通过 composer 安装此包

composer require esign/laravel-linkable

用法

准备您的模型

要使模型具有动态链接,您可以添加 HasDynamicLink 特性。

use Esign\Linkable\Concerns\HasDynamicLink;
use Illuminate\Database\Eloquent\Model;

class MenuItem extends Model
{
    use HasDynamicLink;
}

您的数据库结构应如下所示

Schema::create('menu_items', function (Blueprint $table) {
    $table->id();
    $table->string('dynamic_link_type')->nullable();
    $table->string('dynamic_link_url')->nullable();
    $table->string('dynamic_link_linkable_model')->nullable();
});

内部链接

如果您将 dynamic_link_type 设置为 internal,则将使用 dynamic_link_linkable_model 字段。为了知道内部动态链接应该指向何处,您可以在相关模型上实现 LinkableUrlContract

use Esign\Linkable\Contracts\LinkableUrlContract;

class Post extends Model implements LinkableUrlContract
{
    public function linkableUrl(): ?string
    {
        return "https:///posts/{$this->id}";
    }
}

外部链接

如果您将 dynamic_link_type 设置为 external,则将使用 dynamic_link_url 字段。此字段的值应该是一个有效的 URL,例如 https://www.example.com

存储链接

此包提供的是 SingleColumnMorphTo 关系,而不是常规的 MorphTo 关系。一些 CMS(包括我们自己的)不允许基于两列的 morphable 关系,例如 dynamic_link_linkable_typedynamic_link_linkable_idSingleColumnMorphTo 将类型和 id 字段合并到单个列中,例如 dynamic_link_linkable_model。此单列的值存储为 {model}:{id} 格式,例如 post:1。您可以使用完全限定的类名或来自应用程序的 morph map 的值,就像常规的 morphTo 关系一样。

注意 此方法不是理想的,并且使用此关系进行的某些复杂查询可能无法按预期工作。如果您能够,您可以重写 dynamicLinkLinkable 关系以使用 Laravel 的默认 MorphTo 关系。

链接概述

要创建所有可能链接的概述,您可以创建一个 MySQL 视图,该视图创建所有可能链接到的所有可能的模型 联合

DB::statement('
    CREATE OR REPLACE VIEW linkables AS
    SELECT
        CONCAT("post:", id) AS id,
        "post" AS linkable_type,
        id AS linkable_id,
        CONCAT("Post - ", title) AS label
    FROM posts
    UNION
    SELECT
        CONCAT("comment:", id) AS id,
        "comment" AS linkable_type,
        id AS linkable_id,
        CONCAT("Comment - ", title) AS label
    FROM comments
');

这将生成以下输出

渲染动态链接

此包提供了一个视图组件,可帮助您渲染内部和外部链接。

use Esign\Linkable\Concerns\HasDynamicLink;
use App\Models\Post;
use App\Models\MenuItem;

$post = Post::create();
$menuItemInternal = MenuItem::create([
    'dynamic_link_type' => HasDynamicLink::$linkTypeInternal,
    'dynamic_link_url' => null,
    'dynamic_link_linkable_model' => "post:{$post->id}",
]);

$menuItemExternal = MenuItem::create([
    'dynamic_link_type' => HasDynamicLink::$linkTypeExternal,
    'dynamic_link_url' => 'https://www.esign.eu',
    'dynamic_link_linkable_model' => null,
]);

当提供类型为 external 的模型时,视图组件将渲染一个 <a> 标签,并应用 target="_blank"rel="noopener" 属性。

<x-linkable-dynamic-link :model="$menuItemInternal">Esign</x-linkable-dynamic-link>
<a href="https://www.esign.eu/posts/1">Esign</a>
<x-linkable-dynamic-link :model="$menuItemExternal">Esign</x-linkable-dynamic-link>
<a href="https://www.esign.eu" target="_blank" rel="noopener">Esign</a>

扩展此包

创建自己的动态链接类型

此 Laravel 包默认内置了对 内部外部 链接的支持。然而,在某些场景中,您可能希望引入自定义链接类型,例如引用锚点标签。要实现这一点,您可以扩展包的功能。

  1. 扩展 HasDynamicLink 特性
namespace App\Models\Concerns;

use Esign\Linkable\Concerns\HasDynamicLink as BaseHasDynamicLink;

trait HasDynamicLink
{
    use BaseHasDynamicLink {
        dynamicLink as baseDynamicLink;
    }

    public static string $linkTypeAnchor = 'anchor';

    public function dynamicLink(): ?string
    {
        return match ($this->dynamicLinkType()) {
            static::$linkTypeAnchor => $this->dynamicLinkUrl(),
            default => $this->baseDynamicLink(),
        };
    }
}
  1. 创建自己的视图组件

接下来,您需要创建自己的视图组件,该组件扩展了包提供的 DynamicLink 组件。以下是实现方法

namespace App\View\Components;

use App\Models\Concerns\HasDynamicLink;
use Esign\Linkable\View\Components\DynamicLink as BaseDynamicLink;

class DynamicLink extends BaseDynamicLink
{
    public function render(): ?View
    {
        return match ($this->model->dynamicLinkType()) {
            HasDynamicLink::$linkTypeAnchor => view('linkable.dynamic-link-anchor'),
            default => parent::render(),
        };
    }
}
<a {{ $attributes->merge(['href' => $model->dynamicLink()]) }}>{{ $slot }}</a>
  1. 使用自定义视图组件

现在,您可以在 Blade 模板中使用自己的视图组件,而不是包提供的组件

<x-dynamic-link :model="$modelReferencingAnchorTag">
    My anchor tag
</x-dynamic-link>

测试

composer test

许可证

MIT许可证(MIT)。请参阅许可证文件获取更多信息。