Recommended reading
Build table
As mentioned in the next article, the compilation of recommended reading is realized through collection.
As usual, look at the project design draft first, and then design the table structure.
Schema::create('collections'.function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('avatar');
$table->string('description');
$table->unsignedInteger('post_count')->default(0);
$table->unsignedInteger('fans_count')->default(0);
$table->unsignedInteger('user_id')->comment('Creator');
$table->timestamps();
});
Copy the code
The topic exists as collection_admin, collection_author, collection_follower, and collection_post For example, collection_POST is an intermediate table. It is collection and POST.
Schema::create('collection_post'.function (Blueprint $table) {
$table->unsignedInteger('post_id');
$table->unsignedInteger('collection_id');
$table->timestamp('passed_at')->nullable()->comment('Approval time');
$table->timestamps();
$table->index('post_id');
$table->index('collection_id');
$table->unique(['post_id'.'collection_id']);
});
Copy the code
After you’ve created the table, fill in the Seeder.
modeling
# Collection.php
namespace App\Models;
class Collection extends Model
{
public function posts(a)
{
return $this->belongsToMany(Post::class, 'collection_post'); }}Copy the code
# Post.php
namespace App\Models;
class Post extends Model
{
// ...
public function collections(a)
{
return $this->belongsToMany(Collection::class, 'collection_post'); }}Copy the code
With the Collection, you can now implement the last part of your post detail page design
Project income
The first is the feature section, where RESTful specifications allow us to design an API like this
Test.com/api/posts/ {… , here the coding is relatively simple, refer to the source code
Recommended reading
The first step is to design the API according to the RESTful specification
Test.com/api/posts/ {…
Corresponding controller code
# PostController.php
public function indexOfRecommend($post)
{
$collectionIds = $post->collections()->pluck('id');
$query = Post::whereHas('collections'.function ($query) use ($collectionIds) {
$query->whereIn('collection_id', $collectionIds);
});
// Sort problems
$posts = $query->columns()->paginate();
return PostResource::make($posts);
}
Copy the code
As a caveat, the whereHas provided by Laravel generates an inefficient SQL statement that loads the full table. But the purpose of the series is to write descriptive RESTful apis, so no further optimization will be done here.
Observer
The Observer is both an Observer and can be used for code decoupling to keep the controller simple. The next two pieces of logic cover Observer usage scenarios.
The heat
$posts = $query->columns()->paginate(); If order Derby is not specified in this statement, MySQL will fetch the posts in order of ID, ASC, but in general community sites, there will usually be a heat, and then fetch the posts in order of heat.
This part of the sorting algorithm and many, according to the product given formula calculation can be
The following assumes that heat = a * (timestamp – 1546300800) + B * read_count + C * like_count
A/B/C represents the weight of each feature, which can be adjusted at any time according to operational requirements. Because the timestamp is too large, the timestamp number is reduced by subtractingthe timestamp 1546300800 of 2019-01-01. Of course, even so, a will still be a large number, so the value of A will be very small
Schema::create('posts'.function (Blueprint $table) {
// ...
$table->integer('heat')->index()->comment('heat');
// ...
});
Copy the code
Since the project is in development, we modify the original Migration directly and add the HEAT field. Then perform
> php artisan migrate:refresh --seed
Observe observe observe observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe Observe observe observe observe observe observe observe observe observe observe observe observe observe
Once the observer is created from the document and registered, you can write the relevant code
> php artisan make:observer PostObserver --model=Models/Post
class PostObserver
{
/ * * *@param Post $post
*/
public function saving(Post $post)
{
if ($post->isDirty(['like_count'.'read_count'])) {
$heat = 0.001 * ($post->created_at->timestamp - 1546300800)
+ 10 * $post->read_count
+ 1000* $post->like_count; $post->heat = (integer)$heat; }}}Copy the code
Calls to $model->save/update/create trigger the saving method before persisting to the database.
Create a comment
Basic coding
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\Comment;
use App\Resources\CommentResource;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class CommentController extends Controller
{
/ * * *@param \Illuminate\Http\Request $request
* @return \Illuminate\Contracts\Routing\ResponseFactory|Response
*/
public function store(Request $request)
{
$data = $request->all();
$data['user_id'] = \Auth::id();
$data['floor'] = Comment::where('post_id', $request->input('post_id'))->max('floor') + 1;
$comment = Comment::create($data);
// In RESTful specifications, a 201 status code is returned after a successful creation
return \response(CommentResource::make($comment), 201); }}Copy the code
Model
namespace App\Models;
use Staudenmeir\EloquentEagerLimit\HasEagerLimit;
class Comment extends Model
{
use HasEagerLimit;
protected $fillable = ['content'.'user_id'.'post_id'.'floor'.'selected'];
public function getLikeCountAttribute(a)
{
return $this->attributes['like_count']????0;
}
public function getReplyCountAttribute(a)
{
return $this->attributes['reply_count']????0;
}
Copy the code
Because the create method is used, you need to declare $fillable in the model
Because the default values for LIKE_count and reply_count are 0, create does not set LIKE_count, reply_count. But that would leave $comment in the controller’s store method without the like_count and reply_count keys, which is very front-end unfriendly. For example in VUE the usual approach here is this.ments.push (comment). There are two ways to solve this problem
-
$data[‘like_count’] = 0 and $data[‘reply_count’] = 0
-
Set the default values for both keys using the model modifier (illustrated in the Comment model above)
Using either of these methods ensures that the query is consistent with the data at creation time.
API presentation, corresponding Postman documentation attached at the end of the article
In the controller code, the corresponding Model is assigned to tree-QL processing, so you can still use include to ensure the corresponding data consistency.
There is a redundancy of comment_count in the posts table, so when creating a comment, you also need the corresponding post.ment_count + 1. Create and register CommentObserver. Then complete the coding
# CommentObserver.php
namespace App\Observers;
use App\Models\Comment;
class CommentObserver
{
public function created(Comment $comment)
{
$comment->post()->increment('comment_count'); }}Copy the code
supplement
Post release process
A possible problem is that when a user wants to modify an already published post again, if the half-modified post triggers the automatic saving mechanism, the half-modified post will be displayed on the home page, etc.
So instead of a Posts table, you need to add a single table of drafts to serve as a draft box, where users create and modify their drafts, except when they click on a post, to synchronize the corresponding drafts to the Posts table. The relevant process can refer to the brief book.
Publish process coding sample
# DraftController.php
public function published(Draft $draft)
{
Validator::make($draft->getAttributes(), [
'title'= >'required|max:255'.'content'= >'required'
])->validate();
$draft->published();
return response(null.201);
}
Copy the code
public function published(a)
{
if (!$this->post_id) {
$post = Post::create([
'user_id'= >$this->user_id,
'title'= >$this->title,
'content'= >$this->content,
'published_at'= >$this->freshTimestampString(),
]);
$this->post_id = $post->id;
$this->save();
} else {
$post = Post::findOrFail($this->post_id);
$post->title = $this->title;
$post->content = $this->content; $post->save(); }}Copy the code
Refer to the source code for the rest and the Postman documentation for the API.
related
- Api Document documenter.getpostman.com/view/150062…
- Telescope, an online debugging tool
- This section source weiwenhao/ community-API
- Api Tool weiwenhao/tree-ql
- The previous section wrote a descriptive RESTful API (I): Workflow