lyrasoft/feedback

LYRASOFT feedback package

Installs: 0

Dependents: 0

Suggesters: 0

Security: 0

Stars: 0

Watchers: 1

Forks: 0

Open Issues: 0

Type:windwalker-package

1.0.0 2025-01-06 14:23 UTC

This package is auto-updated.

Last update: 2025-01-06 14:27:03 UTC


README

Lyrasoft Feedback package, contains comments and rating functions.

Installation

Install from composer

composer require lyrasoft/feedback

Then copy files to project

php windwalker pkg:install lyrasoft/feedback -t routes -t migrations -t seeders

Language Files

Add this line to admin & front middleware if you don't want to override languages:

$this->lang->loadAllFromVendor('lyrasoft/feedback', 'ini');

// OR

$this->lang->loadAllFromVendor(\Lyrasoft\Feedback\FeedbackPackage::class, 'ini');

Or run this command to copy languages files:

php windwalker pkg:install lyrasoft/feedback -t lang

Seeders

There are 2 example seeders auto installed, add comment-seeder.php and rating-seeder.php to resources/seeders/main.php

return [
    // ...

    __DIR__ . '/comment-seeder.php',
    __DIR__ . '/rating-seeder.php',

    // ...
];

If you don't need example seeders, write your own seeder by services:

foreach ($articleIds as $articleId) {
    foreach (range(1, random_int(2, 5)) as $i) {
        $userId = $faker->randomElement($userIds);

        $item = $commentService->addComment(
            $type,
            $articleId,
            $faker->paragraph(4),
            $userId,
            extra: function (Comment $item) use ($faker) {
                $item->setTitle($faker->sentence(2));
                $item->setCreated($faker->dateTimeThisYear());
                $item->setOrdering($item->count() + 1);
            }
        );
    }
}

Register Admin Menu

Edit resources/menu/admin/sidemenu.menu.php

You must add type to route, every comment should contains type.

// Comment: Article
$menu->link('評論管理: 文章')
    ->to($nav->to('comment_list')->var('type', 'article'))
    ->icon('fal fa-comments');

Comments

Add a comment to a type:

/** @var \Lyrasoft\Feedback\Service\CommentService $commentService */
$commentService->addComment(
    'flower', // Type
    $targetId, // Target ID
    'Comment Text...', // Content
    $user->getId(), // User ID
);

Add a comment and configure Comment entity:

use Lyrasoft\Feedback\Entity\Comment;

/** @var \Lyrasoft\Feedback\Service\CommentService $commentService */
$commentService->addComment(
    'flower', // Type
    $targetId, // Target ID
    'Comment Text...', // Content
    $user->getId(), // User ID
    
    // The extra can be callback or array
    extra: function (Comment $comment) {
        $comment->setRating(5); // If user mark as 5 star
        $comment->setNickname('Another nickname');
    }
);

Comments ordering:

/** @var \Lyrasoft\Feedback\Service\CommentService $commentService */
$commentService->addComment(
    'flower', // Type
    $targetId, // Target ID
    'Comment Text...', // Content
    $user->getId(), // User ID or User entity
    extra: function (Comment $comment) {
        // This optional if you want to set ordering to one comment
        $comment->setOrdering($comment->count() + 1);
    }
);

// Or reorder all comments of one target item.
$commentService->reorderComments(
    'flower', // Type
    $targetId, // Target ID
);

Comment Reply

There are 2 ways to add reply, one is just write reply content to comment, every comment contains only 1 reply:

/** @var \Lyrasoft\Feedback\Service\CommentService $commentService */

$commentService->addInstantReply(
    $comment, // Can be ID or entity
    'Reply text...',
    $user->getId(), // User ID or User entity
);

The other way is to create sub comments:

/** @var \Lyrasoft\Feedback\Service\CommentService $commentService */

$childComment = $commentService->addSubReply(
    $parentComment, // Can be ID or entity
    'Reply text...',
    $user->getId(), // User ID or User entity
    extra: function (Comment $comment) {
        // Configure comment entity before save
    }
);

// Optional: if you want to reorder it.
$commentService->reorderComments(
    $parentComment->getType(), // Type
    $parentComment->getTargetId(), // Target ID
    $parentComment->getId(), // Parent ID
);

Other Methods

/** @var \Lyrasoft\Feedback\Service\CommentService $commentService */

// Create Comment Item
$comment = $commentService->createCommentItem($type, $targetId, 'text...', $user);

// count Comments
$count = $commentService->countComments($type, $targetId);

// Reorder 
$commentService->reorderComments($type, $targetId);

Rating

Add a rating to a type:

/** @var \Lyrasoft\Feedback\Service\RatingService $ratingService */
$ratingService->addRating(
    'flower', // Type
    $targetId, // Target ID
    $user->getId(), // User ID
);

Add rating if not rated, and configure Comment entity:

use Lyrasoft\Feedback\Entity\Rating;

/** @var \Lyrasoft\Feedback\Service\RatingService $ratingService */
$ratingService->addRatingIfNotRated(
    'flower', // Type
    $targetId, // Target ID
    $user->getId(), // User ID
    
    // The extra can be callback or array
    extra: function (Rating $rating) {
        $rating->setRank(4.5); // If user mark as 4.5 star
    }
);

Rating ordering:

/** @var \Lyrasoft\Feedback\Service\RatingService $ratingService */
$ratingService->addRating(
    'flower', // Type
    $targetId, // Target ID
    $user->getId(), // User ID or User entity
    extra: function (Rating $rating) {
        // This optional if you want to set ordering to one comment
        $rating->setOrdering($rating->count() + 1);
    }
);

// Or reorder all comments of one target item.
$ratingService->reorderRatings(
    'flower', // Type
    $targetId, // Target ID
);

Other Methods

/** @var \Lyrasoft\Feedback\Service\RatingService $ratingService */

// Calc average rank
$avg = $ratingService->calcAvgRank($type, $targetId);

// Get rating item or check is rated
$item = $ratingService->getRating($type, $targetId);
$bool = $ratingService->isRated($type, $targetId);

Rating AJAX Button

You can add button component in blade templates:

<div class="card c-item-card">
    <x-rating-button
        type="item"
        :id="$item->getId()"
        :rated="$item->rated"
        class="..."
    ></x-rating-button>

    <div class="card-body">
        ...
    </div>
</div>

Available params:

AJAX Type Protect

By default, favorite package will not allow any types sent from browser.

You can configre allowed types in config file:

return [
    'feedback' => [
        // ...

        'rating' => [
            'ajax_type_protect' => true,
            'ajax_allow_types' => [
                'article',
                '...' // <-- Add your new types here
            ]
        ],
    ]
];

You can also set the ajax_type_protect to FALSE but we don't recommend to do this.

AJAX Events

You can listen events after rated actions:

// Select all favorite buttons, you can use your own class to select it.
const buttons = document.querySelectorAll('[uni-rating-button]');

for (const button of buttons) {
  button.addEventListener('rated', (e) => {
    u.notify(e.detail.message, 'success');
    
    // Available details
    e.detail.rated;
    e.detail.type;
    e.detail.task;
    e.detail.message;
  });
}

Or listen globally:

document.addEventListener('rated', (e) => {
  if (e.detail.type === 'comment') {
    if (e.detail.favorited) {
      u.notify('已按讚', 'success');
    } else {
      u.notify('已收回讚', 'success');
    }
  }
});

Add Button to Vue App

Use uni-rating-button directive to auto enable button in Vue app.

<a href="javascript://"
    uni-favorite-button
    :data-rated="rated"
    :data-type="type"
    data-class-active=""
    data-class-inactive=""
    data-icon-active="fas fa-heart"
    data-icon-inactive="far fa-heart"
    data-title-active="..."
    data-title-inactive="..."
>
    <i></i>
</a>

Use RatingRepository

Join to List

use Lyrasoft\Feedback\Repository\RatingRepository;

    // In any repository

    public function getFrontListSelector(?User $user = null): ListSelector
    {
        $selector = $this->getListSelector();

        if ($user && $user->isLogin()) {
            RatingRepository::joinRating(
                $selector,
                'item',
                $user->getId(),
                'item.id'
            );
        }
        
        // ...

In blade:

@foreach ($items of $item)
<div>
    ...
    <x-rating-button
        type="item"
        :id="$item->getId()"
        :rated="$item->rated"
        class="..."
    ></x-rating-button>
    ...
</div>
@endforeach