Doctrine:从User实体获取所有未读通知实体

时间:2015-11-16 14:09:37

标签: symfony doctrine-orm

我有一个Store实体,我可以使用getNotifications()方法从中获取为商店设置的所有通知。

我在Notification实体中添加了一个字段,并将其命名为“isRead”。它是布尔值。

现在,我只想从Store实体获取未读通知。

我应该在哪里放置方法getUnreadNotifications()

UPDATE 更清楚一点:如果我有名为“My Awesome Store”的商店并且该商店有10个通知,我想在页面上显示商店本身的信息以及所有10个通知。这些通知必须由字段isRead过滤,因此仅显示isRead = 0的通知。 所以我想从数据库中只选择这些通知,而不是所有通知,然后过滤掉那些已经读过的通知。

控制器的代码:

/**
 * @Route("store/{id}", name="showStore")
 * @Template()
 * @param $id
 * @return array
 */
public function showAction($id)
{
    // Get store info
    $store = $this->getDoctrine()->getRepository('AppBundle:Store')->find($id);

    ...

    // Get Orders
    $orders = $this->getDoctrine()->getRepository('AppBundle:Order')->findByChannel($store->getId());

    ...

    // Check if the current user is the owner of the store
    if (true === $isOwner) {
        ...

        /**
         * HERE IS THE PROBLEM
         * but I think I should use the same solution
         * I used to get Orders: a new query using the
         * Notifications repository.
         */
        $return['notifications'] = $store->getUnreadNotifications();

        ...
    }

    return $return;
}

Store实体的代码:

/**
 * Stores
 *
 * @ORM\Table(name="stores")
 * @ORM\Entity(repositoryClass="\AppBundle\Entity\StoreRepository")
 * @ORM\HasLifecycleCallbacks
 */
class Store
{
    ...

    /**
     * @ORM\OneToMany(targetEntity="NotificationStore", mappedBy="forStore")
     */
    private $notifications;

    public function __construct()
    {
        ...

        $this->notifications = new ArrayCollection();

        ...
    }

    ...

    /**
     * @return ArrayCollection
     */
    public function getNotifications()
    {
        return $this->notifications;
    }

    ...
}

通知实体的代码:

/**
 * @ORM\Entity
 */
abstract class Notification
{
    ...

    /**
     * @var boolean
     *
     * @ORM\Column(name="isRead", type="boolean", nullable=false)
     */
    private $isRead = false;

    ...

    public function setIsRead($isRead = false)
    {
        $this->isRead = $isRead;

        return $this;
    }

    public function isRead()
    {
        return $this->isRead;
    }
}

NotificationStore实体的代码:

/**
 * @ORM\Entity
 * @ORM\Table(name="notifications_stores")
 */
class NotificationStore extends Notification
{
    /**
     * @var integer
     *
     * @ORM\ManyToOne(targetEntity="Store", inversedBy="notifications")
     * @ORM\JoinColumn(name="for_store", referencedColumnName="id")
     */
    protected $forStore;

    public function setForStore($forStore)
    {
        $this->forStore = $forStore;

        return $this;
    }

    public function getForStore()
    {
        return $this->code;
    }
}

4 个答案:

答案 0 :(得分:1)

有两种方法可以解决这种情况:

  1. 创建一个存储库StoreRepository并通过使用过滤器“加入”Store来检索notifications实体,该过滤器会过滤通知,即:

    class StoreRepository extends EntityRepository {
        public function findStoreWithNotifications($id) {
            return $this->createQueryBuilder('store')
                ->addSelect('notification')
                ->leftJoin('store.notifications', 'notification', 'WITH', 'notification.isRead IS false')
                ->where('store.id = :storeId')
                ->setParameter('storeId' => $id)
                ->getQuery()
                ->getSingleResult()
            ;
        }
    }
    

    调用findStoreWithNotifications方法将返回Store实体并加入所有Notifications,按读取状态进行过滤。

  2. getUnreadNotifications实体中创建Store方法,并使用Doctrine Criteria过滤通知收集。如果您选择使用此方法,则应该非常谨慎,因为每次调用getUnreadNotifications方法时,都会触发对数据库的 new 查询。

  3. 您选择哪种方法取决于您的情况。

    根据评论更新:

    在您的控制器中,您有:

    $store = $this->getDoctrine()->getRepository('AppBundle:Store')->find($id);
    

    使用我的目标代码,这一行将成为:

    $store = $this->getDoctrine()->getRepository('AppBundle:Store')->findStoreWithNotifications($id);
    

    然后在你的$return变量中,你只会这样做:

    $return['notifications'] = $store->getNotifications();
    

    由于StoreRepository中的加入,因此只会为您提供已过滤的未读通知。

答案 1 :(得分:0)

我会在Store实体中添加/** * Stores * * @ORM\Table(name="stores") * @ORM\Entity(repositoryClass="\AppBundle\Entity\StoreRepository") * @ORM\HasLifecycleCallbacks */ class Store { // ... /** * @return ArrayCollection|Notification[] */ public function getUnreadNotifications() { return $this->notifications->filter(function(Notification $notification) { return !$notification->isRead() }); } // ... } 方法,如下所示:

(defn validate-email
  [email]
  (let [pattern #"[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?"]
    (and (string? email) (re-matches pattern email))))

答案 2 :(得分:0)

你可以尝试这样的事情:

// YourBundle/Entity/StoreRepository.php

/.../  

class StoreRepository extends EntityRepository
{
    public function findByUnreadNotifications($id)
    {
        $query = $this->createQueryBuilder('s')
            ->where('s.id = :idStore')
            ->setParameter('idStore', $id)
            ->leftJoin('s.notifications', 'n')
            ->andwhere('n.isRead = :isRead')
            ->setParameter('isRead', false)
            ->getQuery()
        ;

        return $query->getResult();
    }
}

在你的控制器中:

/.../

$return['notifications'] = $this->getDoctrine()->getRepository('AppBundle:Store')->findByUnreadNotifications($id);

/.../

答案 3 :(得分:0)

最后我将方法添加到NotificationRepository类。 这会产生一个新的查询,但是当通知从通知实体获取时保持代码更清晰,而不会造成混淆。

感谢您的回复! :)