Content
This is an interface of a Contract
content. Example: Blog, Photo v.v...
A Contract
content always has user_id
, user_type
, owner_id
, and owner_type
.
namespace MetaFox\Platform\Contracts;use Illuminate\Database\Eloquent\Builder;use Illuminate\Database\Eloquent\Model;use Illuminate\Database\Eloquent\Relations\BelongsTo;use Illuminate\Database\Eloquent\Relations\MorphTo;use Illuminate\Support\Collection;interface Content extends Entity{/*** @return int*/public function userId(): int;/*** @return string*/public function userType(): string;/*** @return int*/public function ownerId(): int;/*** @return string*/public function ownerType(): string;/*** @return User|MorphTo*/public function user();/*** @return UserEntity|BelongsTo*/public function userEntity();/*** @return User|MorphTo*/public function owner();/*** @return UserEntity|BelongsTo*/public function ownerEntity();}
Category
For example, you may want to organize Note
items into categories, you need to have 2 schemas note_categories
and note_category_data
to keep many-to-many relationship of notes
and categories
Schema
class NoteMigration extends Migration{public function up (){DbTableHelper::categoryTable('note_categories', true);DbTableHelper::categoryDataTable('blog_category_data');}public function down(){Schema::dropIfExists('note_categories');Schema::dropIfExists('note_category_data');}}
Category DDL
-- auto-generated definitionCREATE TABLE note_categories(id serial CONSTRAINT note_categories_pkey PRIMARY KEY,parent_id integer,name varchar(255) NOT NULL,name_url varchar(255),is_active smallint DEFAULT '1'::smallint NOT NULL,ordering integer DEFAULT 0 NOT NULL,total_item integer DEFAULT 0 NOT NULL,created_at timestamp(0),updated_at timestamp(0));
Category Data DDL
-- auto-generated definitionCREATE TABLE note_category_data(id bigserial CONSTRAINT blog_category_data_pkey PRIMARY KEY,item_id bigint NOT NULL,category_id integer NOT NULL);
Tags
Each content can support hashtag and tags
- hashtag is tagged words starting by
#
in description of content. - tag (sometimes named as topics) is separated word/label attached to a content
In order to support tags and search in MetaFox app
Step 1:
Add *_tag_data
relation to migration
DbTableHelper::createTagDataTable('blog_tag_data');
Step 2:
Modify content database table to have tags
class CreateBlogTables extends Migration{function up(){// add this line to up() methodDbTableHelper::tagsColumns($table);}}
Add *TagData
table class
<?phpnamespace MetaFox\Blog\Models;use Illuminate\Database\Eloquent\Builder;use Illuminate\Database\Eloquent\Relations\Pivot;/*** Class BlogTagData.* @mixin Builder* @property int $id* @property int $item_id* @property int $tag_id* @property string $tag_text*/class BlogTagData extends Pivot{/*** @var bool*/public $timestamps = false;/*** @var string*/protected $table = 'blog_tag_data';/*** @var string[]*/protected $fillable = ['item_id','tag_id',];}
Step 3
Associate tags to Blog content
class Blog {/*** @return BelongsToMany*/public function tagData(): BelongsToMany{return $this->belongsToMany(Tag::class,'blog_tag_data','item_id','tag_id')->using(BlogTagData::class);}// ... other method}
Step 4
Add tag scope to associated query to be able to filter content by tag.
if ($searchTag != '') {$query = $query->addScope(new TagScope($searchTag));}
Step 5
On the Search form, there are no tag fields, users can type "#" in search field to search with tags.
class IndexRequest{/*** @return array<string, mixed>*/public function validated(): array{$data = parent::validated();// .. other processif (Str::startsWith($data['q'], '#')) {$data['tag'] = Str::substr($data['q'], 1);$data['q'] = MetaFoxConstant::EMPTY_STRING;}return $data;}}
Policy
This is the main interface for all Policies.
namespace MetaFox\Platform\Contracts\Policy;use MetaFox\Platform\Contracts\User;use MetaFox\Platform\Contracts\Content;interface ResourcePolicyInterface{public function viewAny(User $user, ?User $owner = null): bool;public function view(User $user, Content $resource): bool;public function viewOwner(User $user, User $owner): bool;public function create(User $user, ?User $owner = null): bool;public function update(User $user, ?Content $resource = null): bool;public function delete(User $user, ?Content $resource = null): bool;public function deleteOwn(User $user, ?Content $resource = null): bool;}
Global Policy
When you want to set a global policy to every Resource, you should create classes in packages/[company]/[app_name]/src/Policies/Handlers
folder
In the below example, CanComment
class will add a comment policy to all Policy classes
namespace MetaFox\Comment\Policies\Handlers;use MetaFox\Platform\Contracts\Content;use MetaFox\Platform\Contracts\HasTotalComment;use MetaFox\Platform\Contracts\User;use MetaFox\Platform\Support\Facades\PrivacyPolicy;class CanComment{public function check(string $entityType, User $user, Content $resource): bool{// Code here}}
If your policy has its own comment
method, it will override the global policy method.