2016-12-29 3 views
1

фона:CodeIgniter Модели против Symfony/Doctrine Модели

У меня есть построить мой веб-приложения с помощью CodeIgniter, потому что она была единственной основой я мог понять достаточно легко, чтобы идти быстро. Теперь, увидев невероятно расширенную функциональность Symfony и стандарты PSR, я разобрался, чтобы разобраться во всем этом.

Dialemma

Я не уверен, как подходить к модели слоя с симфони/доктриной. Как я понимаю: доктрина создает класс сущностей для таблицы базы данных, как так ...

enter image description here

Этот класс содержит кучу функций сеттер/добытчика.

В настоящий момент мой ментальный блок состоит в том, что я не понимаю, как я должен добавить функциональность к моему модельному слою.

Чтобы понять, откуда я родом, взгляните на типичную модель CodeIgniter, с которой я сейчас работаю. Он обрабатывает купоны на скидку.

<?php 

/** 
* This class handles all coupon codes 
*/ 

class Coupon_Model extends CI_Model 
{ 
    /** 
    * gets a specific coupon 
    * @param string $coupon_code 
    * @return obj 
    */ 
    public function getCoupon($coupon_code) 
    { 
     $this->db->where('coupon_code', $coupon_code); 
     $query = $this->db->get('coupons'); 
     return $query->row(); 
    } 

    /** 
    * gets all coupons associated with a course 
    * @param int $course_id 
    * @return array 
    */ 
    public function getCourseCoupons($course_id) 
    { 
     $this->db->where('course_id', $course_id); 
     $query = $this->db->get('coupons'); 
     return $query->result(); 
    } 

    /** 
    * generates a string of 10 random alphanumeric numbers 
    * @return string 
    */ 
    public function generateCouponCode() 
    { 
     return strtoupper(substr(base_convert(sha1(uniqid(mt_rand())), 16, 36), 0, 10)); 
    } 

    /** 
    * creates a new active coupon 
    * @param array $data 
    * @param string $coupon_code 
    * @return bool 
    */ 
    public function createCoupon($data, $coupon_code = null) 
    { 
     if ($coupon_code !== '') { 
      $data['coupon_code'] = $coupon_code; 
     } else { 
      $data['coupon_code'] = $this->generateCouponCode(); 
     } 

     return $this->db->insert('coupons', $data); 
    } 

    /** 
    * checks if a coupon is valid 
    * @param string $coupon_code 
    * @param int $course_id 
    * @return bool 
    */ 
    public function checkCoupon($coupon_code, $course_id = null) 
    { 
     $this->db->where('coupon_code', $coupon_code); 
     $query = $this->db->get('coupons'); 
     $coupon = $query->row(); 

     // if coupon code exists 
     if ($coupon === null) { 
      return false; 
     } 

     // if coupon is for the right course 
     if ($coupon->course_id !== $course_id && $course_id !== null) { 
      return false; 
     } 

     // if coupon code has not expired 
     if ($coupon->expiry_date <= $this->Time_Model->getCarbonNow()->timestamp) { 
      return false; 
     } 
     return true; 
    } 

    /** 
    * deletes a coupon record 
    * @param int coupon_id 
    * @return bool 
    */ 
    public function deleteCoupon($coupon_id) 
    { 
     $this->db->where('coupon_id', $coupon_id); 
     return $this->db->delete('coupons'); 
    } 

    /** 
    * applys the coupon discount 
    * @param int $price 
    * @param float $discount (percentage) 
    */ 
    public function applyDiscount($price, $discount) 
    { 
     $price = $price - (($discount/100) * $price); 
     return $price; 
    } 
} 

Как вы можете видеть, что это довольно прямо вперед, если бы я хотел, чтобы добавить функциональность я буквально просто создать новую функцию.

Чтобы использовать эту модель я бы просто загрузить его на контроллер, как это:

$this->model->load('coupons/Coupon_Model'); 
$this->Coupon_Model->getCoupon($coupon_code); 

Простой, сделано и посыпанный ... к сожалению, я не знаю, как реализовать такую ​​функциональность с симфони/доктриной ,

Должен ли я создать новый класс отдельно от объекта и добавить дополнительные функции к этому классу? Или я должен добавить дополнительные функции в класс сущностей?

Возьмем, например, мою простую функцию, которая генерирует код купона:

/** 
    * generates a string of 10 random alphanumeric numbers 
    * @return string 
    */ 
    public function generateCouponCode() 
    { 
     return strtoupper(substr(base_convert(sha1(uniqid(mt_rand())), 16, 36), 0, 10)); 
    } 

Где бы лучшее место, чтобы поставить эту функцию? В разделе AppBundle/models/coupons?

Я ясно понял плохие привычки от CodeIgniter и чувствую, что я приближаюсь к этому неправильно.

+3

Что вы ищете, я считаю, является репозиторием: они позволят вам определять пользовательские запросы. См. Http://symfony.com/doc/current/doctrine/repository.html – SolarBear

+0

согласен с Solarbear. Репозитории - это ключевое слово для вашей проблемы. –

+0

CodeIgniter> Symfony ... – Hackerman

ответ

1

Symfony + Doctrine ORM поставляется с множеством требований по умолчанию для замены моделей CodeIgniter с помощью EntityManager в вашем контроллере.

Например

namespace AppBundle\Controller; 

use Symfony\Component\HttpFoundation\Request; 
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; 

class DefaultController extends Controller 
{ 

    /** 
    * @Route("/{id}/show", name="app_show", defaults={"id" = 1}) 
    */ 
    public function showAction(Request $request, $id) 
    { 
     $em = $this->getDoctrine()->getManager(); 
     if (!$coupon = $em->find('AppBundle:Coupon', $id)) { 
      throw new NotFoundException('Unknown Coupon Specified'); 
     } 

     //see below to see how this was implemented 
     $similarCoupons = $em->getRepository('AppBundle:Coupon') 
          ->filterCourse($coupon->course); 

     return $this->render('AppBundle:template.twig', [ 
      'coupon' => $coupon, 
      'similarCoupons' => $similarCoupons 
     ]); 
    } 

    /** 
    * @Route("/new", name="app_new") 
    */ 
    public function newAction(Request $request) 
    { 
     //use Symfony Form Component instead 
     $em = $this->getDoctrine()->getManager(); 
     $coupon = new \AppBundle\Entity\Coupon; 
     //calls __construct to call generateCouponCode 

     $coupon->setName($request->get('name')); 
     $em->persist($coupon); 
     $em->flush(); 

     return $this->redirectToRoute('app_show', ['id' => $coupon->getId()]); 
    } 

    //... 
} 

Вы хотите задать функциональность, которую каждый объект, чтобы при работе с ним из класса сущностей. Это становится доступным без необходимости повторного посещения репозитория, поскольку сущность никогда не должна знать об EntityManager. Фактически, каждый сущность может считаться их собственными моделями.

Например, $coupon->generateCouponCode(); или $this->generateCouponCode() с человека.

В противном случае вы бы использовали Repository вашего объекта (-ей) базы данных Doctrine, чтобы добавить более сложные функции.

// /src/AppBundle/Entity/Coupon.php 

namespace AppBundle\Entity; 

use Doctrine\ORM\Mapping as ORM; 

/** 
* @ORM\Entity(repository="CouponRepository") 
*/ 
class Coupon 
{ 
    /** 
    * @var integer 
    * @ORM\Column(name="id", type="integer", nullable=false) 
    * @ORM\Id 
    * @ORM\GeneratedValue(strategy="IDENTITY") 
    */ 
    private $id; 

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

    /** 
    * @var string 
    * @ORM\Column(name="coupon_code", type="string", length=10) 
    */ 
    private $couponCode; 

    /** 
    * @var Course 
    * @ORM\ManyToOne(targetEntity="Course", inversedBy="coupons") 
    * @ORM\JoinColumn(name="course", referencedColumnName="id") 
    */ 
    private $course; 

    //... 

    public function __construct() 
    { 
     //optionally create code when persisting a new database entry by using LifeCycleCallbacks or a Listener instead of this line. 
     $this->couponCode = $this->generateCouponCode(); 
    } 

    //... 

    /** 
    * generates a string of 10 random alphanumeric numbers 
    * @return string 
    */ 
    public function generateCouponCode() 
    { 
     return strtoupper(substr(base_convert(sha1(uniqid(mt_rand())), 16, 36), 0, 10)); 
    } 
} 

Затем ваши пользовательские запросы войдут в ваш репозиторий.

// /src/AppBundle/Entity/CouponRepository.php 

namespace AppBundle\Entity; 

use Doctrine\ORM\EntityRepository; 

class CouponRepository extends EntityRepository 
{ 
    /** 
    * filters a collection of Coupons that matches the supplied Course 
    * @param Course $course 
    * @return array|Coupons[] 
    */ 
    public function filterCourse(Course $course) 
    { 
     $qb = $this->createQueryBuilder('c'); 
     $expr = $qb->expr(); 
     $qb->where($expr->eq('c.course', ':course')) 
      ->setParameter('course', $course); 

     return $qb->getQuery()->getResult(); 
    } 

} 

Кроме того, вы можете filter collections объединения (Foreign Key) эталонным в вашей организации.

namespace AppBundle\Entity; 

use Doctrine\Common\Collections\ArrayCollection; 
use Doctrine\Common\Collections\Criteria; 

//... 
class Course 
{ 
    //... 

    /** 
    * @var ArrayCollection|Coupon[] 
    * @ORM\OneToMany(targetEntity="Coupon", mappedBy="course") 
    */ 
    private $coupons; 

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

    /** 
    * @return ArrayCollection|Coupon[] 
    */ 
    public function getCoupons() 
    { 
     return $this->coupons; 
    } 

    /** 
    * @param string $name 
    * @return \Doctrine\Common\Collections\Collection|Coupon[] 
    */ 
    public function getCouponsByName($name) 
    { 
     $criteria = Criteria::create(); 
     $expr = $criteria::expr(); 

     return $this->coupons->matching($criteria->where($expr->eq('name', $name))); 
    } 
} 
+1

Я стараюсь держаться подальше от использования префикса 'get' в методах репозитория, чтобы гарантировать, что он не определен как получатель Entity. Но это только личное предпочтение. – fyrye

+0

Я хочу извиниться за то, что не комментируя раньше, этот индивидуальный пример поможет мне помочь, и я ценю ответ. Я только что пришел в раздел «Репозиторий» моих учебных пособий, так что это здорово. –