2017-02-04 7 views
0

У меня здесь странная проблема, но сначала короткое объяснение того, что представляет собой идея. У нас есть система, где все пользователи могут загружать файлы. У каждого пользователя будут любимые файлы, и мне нужно добавить разбивку на страницы.Symfony3 Doctrine queryBuilder for pagerfanta on ManyToMany realationship

Моя сущность Пользователь:

/** 
* User 
* 
* @ORM\Table(name="users") 
* @ORM\Entity(repositoryClass="STInfoSystemBundle\Repository\UserRepository") 
*/ 
class User implements UserInterface 
{ 
    /** 
    * @var int 
    * 
    * @ORM\Column(name="id", type="integer") 
    * @ORM\Id 
    * @ORM\GeneratedValue(strategy="AUTO") 
    */ 
    private $id; 

    /** 
    * @var string 
    * 
    * @ORM\Column(name="email", type="string", length=100, unique=true) 
    */ 
    private $email; 

    /** 
    * @var string 
    * 
    * @ORM\Column(name="password", type="string", length=255) 
    */ 
    private $password; 

    /** 
    * @var UserDetails 
    * 
    * @ORM\OneToOne(targetEntity="STInfoSystemBundle\Entity\UserDetails", mappedBy="user", cascade={"persist"}) 
    */ 
    private $userDetails; 

    /** 
    * @var ArrayCollection 
    * 
    * @ORM\ManyToMany(targetEntity="STInfoSystemBundle\Entity\Role") 
    * @ORM\JoinTable(name="user_roles", 
    *  joinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id")}, 
    *  inverseJoinColumns={@ORM\JoinColumn(name="role_id", referencedColumnName="id")} 
    * ) 
    * 
    */ 
    private $roles; 

    /** 
    * @var FileUpload[] 
    * @ORM\ManyToMany(targetEntity="STInfoSystemBundle\Entity\FileUpload") 
    * @ORM\JoinTable(name="users_favorites", 
    *  joinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id")}, 
    *  inverseJoinColumns={@ORM\JoinColumn(name="file_id", referencedColumnName="id")}) 
    */ 
    private $favoriteFiles; 

    /** 
    * @var FileUpload[] 
    * 
    * @ORM\OneToMany(targetEntity="STInfoSystemBundle\Entity\FileUpload", mappedBy="user") 
    * 
    */ 
    private $files; 

    /** @var Event[] 
    * @ORM\OneToMany(targetEntity="STInfoSystemBundle\Entity\Event", mappedBy="user") 
    */ 
    private $events; 

    public function __construct() 
    { 
     $this->roles = new ArrayCollection(); 
     $this->files = new ArrayCollection(); 
     $this->favoriteFiles = new ArrayCollection(); 
    } 

    /** 
    * Get id 
    * 
    * @return int 
    */ 
    public function getId() 
    { 
     return $this->id; 
    } 

Мой FileUpload объект:

/** 
* @ORM\Entity 
* @Vich\Uploadable 
* @Table(name="uploaded_files") 
* @ORM\Entity(repositoryClass="STInfoSystemBundle\Repository\FileUploadRepository") 
*/ 
class FileUpload 
{ 
    const FILES_PER_PAGE = 3; 

    /** 
    * @ORM\Id 
    * @ORM\Column(type="integer") 
    * @ORM\GeneratedValue(strategy="AUTO") 
    */ 
    private $id; 
//  *  mimeTypesMessage="Allowed files are pdf and MS word.", 

    /** 
    * NOTE: This is not a mapped field of entity metadata, just a simple property. 
    * 
    * @Vich\UploadableField(mapping="generic_file", fileNameProperty="fileName") 
    * @Assert\File(
    *  maxSize = "5M", 
    *  mimeTypes = {"application/pdf"}, 
    *  maxSizeMessage="The file is too large ({{ size }} {{ suffix }}). Allowed maximum size is {{ limit }} {{ suffix }}." 
    *) 
    * @var File 
    */ 
    private $file; 

    //TODO: ..... other fields if any 

    /** 
    * @ORM\Column(type="string", length=255) 
    * 
    * @var string 
    */ 
    private $fileName; 

    /** 
    * @ORM\Column(type="datetime") 
    * 
    * @var \DateTime 
    */ 
    private $updatedAt; 

    /** 
    * @var 
    * @ORM\ManyToOne(targetEntity="STInfoSystemBundle\Entity\User", inversedBy="files") 
    */ 
    private $user; 

    /** @var ArrayCollection 
    * 
    * @ORM\ManyToMany(targetEntity="STInfoSystemBundle\Entity\User", mappedBy="favoriteFiles") 
    * 
    */ 
    private $favoriteUsers; 

    /** 
    * @var string 
    * 
    * @ORM\Column(name="title", type="string", length=255) 
    */ 
    private $title; 

    /** 
    * @var string 
    * 
    * @ORM\Column(name="description", type="string", length=255) 
    */ 
    private $description; 

    /** @var Specialty 
    * 
    * @ORM\ManyToOne(targetEntity="STInfoSystemBundle\Entity\Specialty", inversedBy="files") 
    */ 
    private $specialty; 

    public function __construct() 
    { 
     $this->favoriteUsers = new ArrayCollection(); 
    } 

    /** 
    * Get id 
    * 
    * @return int 
    */ 
    public function getId() 
    { 
     return $this->id; 
    } 

FileUploadRepository:

/** 
* FileUploadRepository 
* 
* This class was generated by the Doctrine ORM. Add your own custom 
* repository methods below. 
*/ 
class FileUploadRepository extends \Doctrine\ORM\EntityRepository 
{ 
    /** 
    * @param $userId 
    * @return \Doctrine\ORM\Query 
    */ 
    public function findUserMaterialsQuery($user) 
    { 
     return $this->createQueryBuilder('m') 
      ->andWhere('m.user = :user') 
      ->setParameter('user', $user) 
      ->getQuery(); 
    } 

    /** 
    * @param int $page 
    * @param $user 
    * @return Pagerfanta 
    */ 
    public function findUserMaterials($page = 1,$user){ 
     $paginator = new Pagerfanta(new DoctrineORMAdapter($this->findUserMaterialsQuery($user)), false); 
     $paginator->setMaxPerPage(FileUpload::FILES_PER_PAGE); 
     $paginator->setCurrentPage($page); 

     return $paginator; 
    } 

    /** 
    * @param $specialty 
    * @return \Doctrine\ORM\Query 
    */ 
    public function findUserSpecialtyMaterialsQuery($specialty) 
    { 
     return $this->createQueryBuilder('m') 
      ->andWhere('m.specialty = :specialty') 
      ->setParameter('specialty', $specialty) 
      ->getQuery(); 
    } 

    /** 
    * @param int $page 
    * @param $specialty 
    * @return Pagerfanta 
    */ 
    public function findUserSpecialtyMaterials($page = 1,$specialty){ 
     $paginator = new Pagerfanta(new DoctrineORMAdapter($this->findUserSpecialtyMaterialsQuery($specialty)), false); 
     $paginator->setMaxPerPage(FileUpload::FILES_PER_PAGE); 
     $paginator->setCurrentPage($page); 

     return $paginator; 
    } 
} 

UserRepository:

class UserRepository extends \Doctrine\ORM\EntityRepository 
{ 
    /** 
    * @param $userId 
    * @return \Doctrine\ORM\Query 
    */ 
    public function findUserFavoriteMaterialsQuery($userId) 
    { 
     return $this->createQueryBuilder('u') 
      ->addSelect('u.favoriteFiles') 
      ->andWhere('u.id = :userId') 
      ->setParameter('user', $userId) 
      ->getQuery(); 

    } 

    /** 
    * @param int $page 
    * @param $userId 
    * @return Pagerfanta 
    */ 
    public function findUserFavoriteMaterials($page = 1,$userId){ 
     $paginator = new Pagerfanta(new DoctrineORMAdapter($this->findUserFavoriteMaterialsQuery($userId)), false); 
     $paginator->setMaxPerPage(3); 
     $paginator->setCurrentPage($page); 

     return $paginator; 
    } 

} 

materials.html.twig

{% extends 'base.html.twig' %} 

{% block main %} 
    <h4>Favorite/My materials/All materials</h4> 
    {% for material in materials %} 
     <div class="col-sm-4"> 
      <div class="panel panel-default"> 
       <div class="panel-heading"> 
        <h3 class="panel-title">{{ material.title }}</h3> 
       </div> 
       <div class="panel-body"> 
        {{ material.shortDescription }} 
        <hr> 
        <a href="{{ path("material", {id: material.id}) }}" class="">Read</a> 
        <br> 
        <a href="{{ path("toggle_favorite", {id: material.id}) }}" class=""> 
         {% if material.favorite(app.user) %} 
          Remove from favorites 
         {% else %} 
          Add to favorites 
         {% endif %} 
        </a> 
        <br> 
        {% if app.user.isTeacher %} 
         Edit/delete - TO BE DONE 
        {% endif %} 
       </div> 
       <div class="panel-footer"> 
        {{ material.specialty }} 
        {#TODO: pagination#} 
       </div> 
      </div> 
     </div> 
    {% endfor %} 

    <div class="col-sm-12"> 
     {% if materials.haveToPaginate %} 
      <div class="navigation text-center"> 
       {#{{ pagerfanta(events, 'twitter_bootstrap3_translated') }}#} 
       {{ pagerfanta(materials, 'twitter_bootstrap3_translated', { routeName: routeName }) }} 
      </div> 
     {% endif %} 
    </div> 

{% endblock %} 

и здесь является частью MaterialController, которая работает нормально:

/** 
    * @Route("/materials", defaults={"page": "1"}, name="materials") 
    * @Route("/materials/page/{page}", requirements={"page": "[1-9]\d*"}, name="materials_paginated") 
    * 
    */ 
    public function allMaterials($page) 
    { 
     /** @var User $user */ 
     $user = $this->getUser(); 
     $userSpecialty = $user->getUserDetails()->getSpecialty(); 
//  $allMaterials = $this->getDoctrine()->getRepository(FileUpload::class)->findBy([ 
//   'specialty' => $user->getUserDetails()->getSpecialty() 
//  ]); 

     $allMaterials = $this->getDoctrine()->getRepository(FileUpload::class)->findUserSpecialtyMaterials($page, $userSpecialty); 

     $routeName = 'materials_paginated'; 

     return $this->render('material/materials.html.twig', [ 
       'materials' => $allMaterials, 
       'routeName' => $routeName 
      ] 
     ); 
    } 



    /** 
    * @Route("/myMaterials", defaults={"page": "1"}, name="my_materials") 
    * @Route("/myMaterials/page/{page}", requirements={"page": "[1-9]\d*"}, name="my_materials_paginated") 
    */ 
    public function myMaterials($page) 
    { 

     /** @var User $user */ 
     $user = $this->getUser(); 
//  $myMaterials = $user->getFiles(); 
     $myMaterials = $this->getDoctrine()->getRepository(FileUpload::class)->findUserMaterials($page, $user); 

     $routeName = 'my_materials_paginated'; 

     return $this->render('material/materials.html.twig', [ 
       'materials' => $myMaterials, 
       'routeName' => $routeName 
      ] 
     ); 
    } 

но ниже не получает мне что-нибудь:

/** 
    * @Route("/favoriteMaterials", defaults={"page": "1"}, name="favorite_materials") 
    * @Route("/favoriteMaterials/page/{page}", requirements={"page": "[1-9]\d*"}, name="favorite_materials_paginated") 
    * 
    */ 
    public function favoriteMaterials($page) 
    { 
     /** @var User $user */ 
     $user = $this->getUser(); 
//  $favoriteMaterials = $user->getFavoriteFiles(); 

     $favoriteMaterials = $this->getDoctrine()->getRepository(User::class)->findUserFavoriteMaterials($page, $user->getId()); 

     $routeName = 'favorite_materials_paginated'; 

     return $this->render('material/materials.html.twig',[ 
       'materials' => $favoriteMaterials, 
       'routeName' => $routeName 
      ] 
     ); 
    } 

Так как использовать тот же шаблон твига для myMaterials, allMaterials, favoriteMaterials и работать с paginate?

ответ

0

Я нашел решение. Добавлено их к FileUploadRepository

/** 
* @param $user 
* @return \Doctrine\ORM\Query 
*/ 
public function findUserFavoriteMaterialsQuery($user) 
{ 
    return $this->createQueryBuilder('f') 
     ->andWhere(':user MEMBER OF f.favoriteUsers') 
     ->setParameter('user', $user) 
     ->getQuery(); 
} 

/** 
* @param int $page 
* @param $user 
* @param int $perPage 
* @return Pagerfanta 
*/ 
public function findUserFavoriteMaterials($page = 1, $user, $perPage = FileUpload::FILES_PER_PAGE) 
{ 
    $paginator = new Pagerfanta(new DoctrineORMAdapter($this->findUserFavoriteMaterialsQuery($user))); 
    $paginator->setMaxPerPage($perPage); 
    $paginator->setCurrentPage($page); 

    return $paginator; 
} 

Тогда в моем MaterialController я использовал это так:

 /** @var User $user */ 
    $user = $this->getUser(); 

    $favoriteMaterials = $this->getDoctrine()->getRepository(FileUpload::class)->findUserFavoriteMaterials($page, $user); 

    $routeName = 'favorite_materials_paginated'; 
    $title = 'Favorite materials'; 

    return $this->render('material/materials.html.twig', [ 
      'materials' => $favoriteMaterials, 
      'routeName' => $routeName, 
      'title' => $title 
     ] 
    );