Doctrine 2 - ORM
  1. Doctrine 2 - ORM
  2. DDC-2879

Persisting collections with Composite Primary Keys composed of 2 Foreign Keys and one metadata field

    Details

    • Type: Bug Bug
    • Status: Awaiting Feedback
    • Priority: Major Major
    • Resolution: Unresolved
    • Affects Version/s: 2.3.4
    • Fix Version/s: None
    • Component/s: ORM
    • Security Level: All
    • Environment:
      Ubuntu 13.04 and PostgresSQL 9.1.0 on Vagrant Virtual Machine running an application with Symfony2 backend and JavaScript client

      Description

      SYNOPSIS

      Bug prevents persisting a collection of entities in a join table with a Composite Primary
      Key made up of 2 Foreign Keys and one metadata field. From these mapping instructions:
      http://docs.doctrine-project.org/en/latest/tutorials/composite-primary-keys.html#use-case-3-join-table-with-metadata

      ISSUE DETAILS

      SUCCESS: When FOREIGN KEY 1 is the same across items in a collection to be persisted, and FOREIGN KEY 2 is greater than FOREIGN KEY 2 in any existing PRIMARY KEY, the entity and collection are persisted correctly

        • Example: GPA "add val below" exists and has assessment value
          {"grade_point_average_id":1,"assessment_id":1,"value":4}

          We will try to add a new assessment value where assessment_id > that of any existing assessment value for GPA "add val below"

        • Request Payload:
          {"name":"Add Val Below","courses":[],"assessmentValues":[{"assessment":1,"value":4},{"assessment":3,"value":2}]}
        • Debug Log:
          [2014-01-07 11:48:01] app.INFO: START GRADE_POINT_AVERAGE_REPOSITORY #SAVE [GPA #GET_NAME =ADD VAL BELOW] [] []
          [2014-01-07 11:48:01] app.INFO:   BEGIN OUTPUT FOR GRADE POINT AVERAGE Add Val Below - ASSESSMENT VALUE 1 [] []
          [2014-01-07 11:48:01] app.INFO:         ASSESSMENT_VALUE #GET_GRADE_POINT_AVERAGE #GET_ID: 1 [] []
          [2014-01-07 11:48:01] app.INFO:         GRADE_POINT_AVERAGE #GET_ID: 1 [] []
          [2014-01-07 11:48:01] app.INFO:         ASSESSMENT_VALUE #GET_ASSESSMENT #GET_ID: 1 [] []
          [2014-01-07 11:48:01] app.INFO:         ASSESSMENT_VALUE #GET_VALUE: 4 [] []
          [2014-01-07 11:48:01] app.INFO:         MANAGED? 1 [] []
          [2014-01-07 11:48:01] app.INFO:   END OUTPUT FOR GRADE POINT AVERAGE Add Val Below - ASSESSMENT VALUE 2 [] []
          [2014-01-07 11:48:01] app.INFO:   BEGIN OUTPUT FOR GRADE POINT AVERAGE Add Val Below - ASSESSMENT VALUE 2 [] []
          [2014-01-07 11:48:01] app.INFO:         ASSESSMENT_VALUE #GET_GRADE_POINT_AVERAGE #GET_ID: 1 [] []
          [2014-01-07 11:48:01] app.INFO:         GRADE_POINT_AVERAGE #GET_ID: 1 [] []
          [2014-01-07 11:48:01] app.INFO:         ASSESSMENT_VALUE #GET_ASSESSMENT #GET_ID: 3 [] []
          [2014-01-07 11:48:01] app.INFO:         ASSESSMENT_VALUE #GET_VALUE: 2 [] []
          [2014-01-07 11:48:01] app.INFO:         MANAGED?  [] []
          [2014-01-07 11:48:01] app.INFO:   END OUTPUT FOR GRADE POINT AVERAGE Add Val Below - ASSESSMENT VALUE 3 [] []
          [2014-01-07 11:48:01] app.INFO: END GRADE_POINT_AVERAGE_REPOSITORY #SAVE [GPA #GET_NAME =ADD VAL BELOW] [] []
          [2014-01-07 11:48:01] doctrine.DEBUG: "START TRANSACTION" [] []
          [2014-01-07 11:48:01] doctrine.DEBUG: INSERT INTO gpa_assessment_value (point_value, grade_point_average_id, assessment_id) VALUES (?, ?, ?) {"1":2,"2":"1","3":"3"} []
          [2014-01-07 11:48:01] doctrine.DEBUG: UPDATE gpa_assessment_value SET point_value = ? WHERE grade_point_average_id = ? AND assessment_id = ? [4,1,1] []
          [2014-01-07 11:48:01] doctrine.DEBUG: "COMMIT" [] []

      FAILURE: When FOREIGN KEY 1 is the same across items in a collection, and FOREIGN KEY 2 is less than any existing FOREIGN KEY 2, the unit of work tries to INSERT existing entity and does not operate on new entity. The EntityManager thinks it contains() the new entity, but not the old one

        • Example: GPA "add val above" exists and has assessment value
          {"assessment":3,"value":2}

          We will try to add a new assessment value where assessment_id < that of any existing assessment value for GPA "add val above"

        • Request Payload:
          {"name":"Add Val Above","courses":[],"assessmentValues":[{"assessment":1,"value":4},{"assessment":3,"value":2}]}
        • Debug log:
          [2014-01-07 11:47:09] app.INFO: START GRADE_POINT_AVERAGE_REPOSITORY #SAVE [GPA #GET_NAME =ADD VAL ABOVE] [] []
          [2014-01-07 11:47:09] app.INFO:   BEGIN OUTPUT FOR GRADE POINT AVERAGE Add Val Above - ASSESSMENT VALUE 1 [] []
          [2014-01-07 11:47:09] app.INFO:         ASSESSMENT_VALUE #GET_GRADE_POINT_AVERAGE #GET_ID: 2 [] []
          [2014-01-07 11:47:09] app.INFO:         GRADE_POINT_AVERAGE #GET_ID: 2 [] []
          [2014-01-07 11:47:09] app.INFO:         ASSESSMENT_VALUE #GET_ASSESSMENT #GET_ID: 1 [] []
          [2014-01-07 11:47:09] app.INFO:         ASSESSMENT_VALUE #GET_VALUE: 4 [] []
          [2014-01-07 11:47:09] app.INFO:         MANAGED? 1 [] []
          [2014-01-07 11:47:09] app.INFO:   END OUTPUT FOR GRADE POINT AVERAGE Add Val Above - ASSESSMENT VALUE 2 [] []
          [2014-01-07 11:47:09] app.INFO:   BEGIN OUTPUT FOR GRADE POINT AVERAGE Add Val Above - ASSESSMENT VALUE 2 [] []
          [2014-01-07 11:47:09] app.INFO:         ASSESSMENT_VALUE #GET_GRADE_POINT_AVERAGE #GET_ID: 2 [] []
          [2014-01-07 11:47:09] app.INFO:         GRADE_POINT_AVERAGE #GET_ID: 2 [] []
          [2014-01-07 11:47:09] app.INFO:         ASSESSMENT_VALUE #GET_ASSESSMENT #GET_ID: 3 [] []
          [2014-01-07 11:47:09] app.INFO:         ASSESSMENT_VALUE #GET_VALUE: 2 [] []
          [2014-01-07 11:47:09] app.INFO:         MANAGED?  [] []
          [2014-01-07 11:47:09] app.INFO:   END OUTPUT FOR GRADE POINT AVERAGE Add Val Above - ASSESSMENT VALUE 3 [] []
          [2014-01-07 11:47:09] app.INFO: END GRADE_POINT_AVERAGE_REPOSITORY #SAVE [GPA #GET_NAME =ADD VAL ABOVE] [] []
          [2014-01-07 11:47:09] doctrine.DEBUG: "START TRANSACTION" [] []
          [2014-01-07 11:47:09] doctrine.DEBUG: INSERT INTO gpa_assessment_value (point_value, grade_point_average_id, assessment_id) VALUES (?, ?, ?) {"1":2,"2":"2","3":"3"} []
          [2014-01-07 11:47:09] doctrine.DEBUG: "ROLLBACK" [] []
          [2014-01-07 11:47:09] event.DEBUG: Notified event "kernel.exception" to listener "Symfony\Component\Security\Http\Firewall\ExceptionListener::onKernelException". [] []
          [2014-01-07 11:47:09] event.DEBUG: Notified event "kernel.exception" to listener "Symfony\Component\HttpKernel\EventListener\ProfilerListener::onKernelException". [] []
          [2014-01-07 11:47:09] event.DEBUG: Notified event "kernel.exception" to listener "Symfony\Component\HttpKernel\EventListener\ExceptionListener::onKernelException". [] []
          [2014-01-07 11:47:09] request.CRITICAL: Uncaught PHP Exception Doctrine\DBAL\DBALException: "An exception occurred while executing 'INSERT INTO gpa_assessment_value (point_value, grade_point_average_id, assessment_id) VALUES (?, ?, ?)' with params [2, "2", "3"]:
          
          SQLSTATE[23505]: Unique violation: 7 ERROR:  duplicate key value violates unique constraint "gpa_assessment_value_pkey"
          DETAIL:  Key (grade_point_average_id, assessment_id)=(2, 3) already exists." at /vagrant/vendor/doctrine/dbal/lib/Doctrine/DBAL/DBALException.php line 47 {"exception":"[object] (Doctrine\\DBAL\\DBALException: An exception occurred while executing 'INSERT INTO gpa_assessment_value (point_value, grade_point_average_id, assessment_id) VALUES (?, ?, ?)' with params [2, \"2\", \"3\"]:\n\nSQLSTATE[23505]: Unique violation: 7 ERROR:  duplicate key value violates unique constraint \"gpa_assessment_value_pkey\"\nDETAIL:  Key (grade_point_average_id, assessment_id)=(2, 3) already exists. at /vagrant/vendor/doctrine/dbal/lib/Doctrine/DBAL/DBALException.php:47, PDOException: SQLSTATE[23505]: Unique violation: 7 ERROR:  duplicate key value violates unique constraint \"gpa_assessment_value_pkey\"\nDETAIL:  Key (grade_point_average_id, assessment_id)=(2, 3) already exists. at /vagrant/vendor/doctrine/dbal/lib/Doctrine/DBAL/Statement.php:138)"} []
             

      CODE

      migration.sql
      CREATE TABLE assessment
      (
          id       bigserial NOT NULL,
          scale_id bigint    NOT NULL,
          title    varchar   NOT NULL,
          passing  boolean   NOT NULL,
          rank     int,
      
          PRIMARY KEY (id)
      );
      
      CREATE TABLE assessment_scale
      (
          id   bigserial NOT NULL,
          name varchar   NOT NULL,
      
          PRIMARY KEY (id)
      );
      
      -- ...
      
      CREATE TABLE grade_point_average
      (
          id                         bigserial       NOT NULL,
          name                       varchar         NOT NULL,
          additional_credit_allowance numeric(4, 2),
      
          PRIMARY KEY (id)
      );
      
      -- ...
      
      CREATE TABLE gpa_assessment_value
      (
          grade_point_average_id bigint        NOT NULL,
          assessment_id          bigint        NOT NULL,
          point_value            numeric(4, 2) NOT NULL,
      
          PRIMARY KEY (assessment_id, grade_point_average_id),
          FOREIGN KEY (assessment_id) REFERENCES assessment,
          FOREIGN KEY (grade_point_average_id) REFERENCES grade_point_average
      );
      
      GradePointAverage.php
      <?php
      namespace LGSConnect\Model;
      
      use Doctrine\ORM\Mapping\Entity;
      use Doctrine\ORM\Mapping\Id;
      use Doctrine\ORM\Mapping\GeneratedValue;
      use Doctrine\ORM\Mapping\Column;
      //...
      use Doctrine\Common\Collections\Collection;
      use Doctrine\Common\Collections\ArrayCollection;
      use LGSConnect\Util\ConstructorArgs;
      use LGSConnect\Model\GradePointAverage\AssessmentValue;
      // ...
      
      /**
       * @Entity("LGSConnect\Repository\GradePointAverageRepository")
       */
      class GradePointAverage
      {
          // GradePointAverage Model (owning side): a tool for evaluating a student's performance 
          // by dividing the total points earned by total credits attempted.
      
          use ConstructorArgs;
      
          /**
           * @Id
           * @GeneratedValue
           * @Column(type="bigint")
           *
           * @var int
           */
          private $id;
      
          // ...
      
          /**
           * @OneToMany(targetEntity="LGSConnect\Model\GradePointAverage\AssessmentValue", mappedBy="gradePointAverage", cascade="persist")
           *
           * @var Collection
           */
          private $assessmentValues;
          
          // ...
      
          /**
           * @param array $args
           */
          public function __construct(array $args = [])
          {
              $this->assessmentValues = new ArrayCollection;
              // ...
              $this->handleArgs($args);
          }
          
          // ...
          
          /**
           * @return Collection
           */
          public function getAssessmentValues()
          {
              return $this->assessmentValues;
          }
      
          /**
           * @param ArrayCollection $assessmentValues
           */
          public function setAssessmentValues(ArrayCollection $assessmentValues)
          {
              $this->assessmentValues = $assessmentValues;
          }
      
          /**
           * @param AssessmentValue $assessmentValue
           */
          public function addAssessmentValue(AssessmentValue $assessmentValue)
          {
              $this->assessmentValues->add($assessmentValue);
          }
      
          /**
           * @param AssessmentValue $assessmentValue
           */
          public function removeAssessmentValue(AssessmentValue $assessmentValue)
          {
              $this->assessmentValues->removeElement($assessmentValue);
          }
          
          // ...
      }
      
      AssessmentValue.php
      <?php
      namespace LGSConnect\Model\GradePointAverage;
      
      use Doctrine\ORM\Mapping\Entity;
      use Doctrine\ORM\Mapping\Table;
      use Doctrine\ORM\Mapping\Column;
      use Doctrine\ORM\Mapping\Id;
      use Doctrine\ORM\Mapping\GeneratedValue;
      use Doctrine\ORM\Mapping\ManyToOne;
      use Doctrine\ORM\Mapping\JoinColumn;
      use LGSConnect\Model\GradePointAverage;
      use LGSConnect\Model\Assessment;
      use LGSConnect\Util\ConstructorArgs;
      
      /**
       * @Entity("LGSConnect\Repository\GradePointAverage\AssessmentValueRepository")
       * @Table("gpa_assessment_value")
       */
      class AssessmentValue
      {
          // AssessmentValue Model (inverse side): a number of points assigned 
          // to an Assessment by a Grade Point Average
      
          use ConstructorArgs;
      
          /**
           * @Id
           * @ManyToOne(targetEntity="LGSConnect\Model\GradePointAverage")
           */
          private $gradePointAverage;
      
          /**
           * @Id
           * @ManyToOne(targetEntity="LGSConnect\Model\Assessment")
           */
          private $assessment;
      
          /**
           * @Column("point_value")
           *
           * @var float
           */
          private $value;
      
          /**
           * @param array $args
           */
          public function __construct(array $args = [])
          {
              $this->handleArgs($args);
          }
      
          /**
           * @return GradePointAverage
           */
          public function getGradePointAverage()
          {
              return $this->gradePointAverage;
          }
      
          /**
           * @param GradePointAverage $gradePointAverage
           */
          public function setGradePointAverage(GradePointAverage $gradePointAverage)
          {
              $this->gradePointAverage = $gradePointAverage;
          }
      
          /**
           * @return Assessment
           */
          public function getAssessment()
          {
              return $this->assessment;
          }
      
          /**
           * @param Assessment $assessment
           */
          public function setAssessment(Assessment $assessment)
          {
              $this->assessment = $assessment;
          }
      
          /**
           * @return float
           */
          public function getValue()
          {
              return $this->value;
          }
      
          /**
           * @param float $value
           */
          public function setValue($value)
          {
              $this->value = $value;
          }
      
          /**
           * @return AssessmentScale
           */
          public function getAssessmentScale()
          {
              return $this->assessment->getScale();
          }
      }
      
      Assessment.php
      <?php
      namespace LGSConnect\Model;
      
      use Doctrine\ORM\Mapping\Entity;
      use Doctrine\ORM\Mapping\Id;
      use Doctrine\ORM\Mapping\GeneratedValue;
      use Doctrine\ORM\Mapping\Column;
      use Doctrine\ORM\Mapping\ManyToOne;
      use LGSConnect\Model\Assessment\Scale;
      use LGSConnect\Util\ConstructorArgs;
      
      /**
       * @Entity("LGSConnect\Repository\AssessmentRepository")
       */
      class Assessment
      {
          // Assessment (related, but unmapped): A "grade" assigned to a student 
          // for attending a course section
      
          use ConstructorArgs;
      
          /**
           * @Id
           * @GeneratedValue
           * @Column(type="bigint")
           *
           * @var int
           */
          private $id;
          
          // ...
      
          /**
           * @param array $args
           */
          public function __construct(array $args = [])
          {
              $this->handleArgs($args);
          }
      
          /**
           * @return int
           */
          public function getId()
          {
              return $this->id;
          }
          
          // ...
      }
      
      GradePointAverageRepository.php
      <?php
      namespace LGSConnect\Repository;
      
      use Doctrine\ORM\EntityRepository;
      // ...
      use LGSConnect\Model\GradePointAverage;
      
      class GradePointAverageRepository extends BaseRepository implements GradePointAverageRepositoryInterface
      {
          // ...
      
          /**
           * @param GradePointAverage $gradePointAverage
           */
          public function save(GradePointAverage $gradePointAverage)
          {
              $this->getEntityManager()->persist($gradePointAverage);
              $this->getEntityManager()->flush();
          }
      }
      
      AssessmentValueRepository.php
      <?php
      namespace LGSConnect\Repository\GradePointAverage;
      
      use Doctrine\ORM\EntityRepository;
      use LGSConnect\Model\GradePointAverage\AssessmentValue;
      
      class AssessmentValueRepository extends EntityRepository
      {
          /**
           * @param AssessmentValue $assessmentValue
           */
          public function save(AssessmentValue $assessmentValue)
          {
              $this->getEntityManager()->persist($assessmentValue);
              $this->getEntityManager()->flush();
          }
      }
      
      GradePointAverageManager.php
      <?php
      namespace LGSConnect\Manager;
      
      use InvalidArgumentException;
      use Symfony\Component\Validator\ValidatorInterface;
      use JMS\DiExtraBundle\Annotation\Service;
      use JMS\DiExtraBundle\Annotation\InjectParams;
      use JMS\SecurityExtraBundle\Annotation\PreAuthorize;
      use Knp\Component\Pager\Pagination\PaginationInterface;
      use LGSConnect\Repository\GradePointAverageRepository;
      use LGSConnect\PaginationFactory\GradePointAveragePaginationFactoryInterface;
      use LGSConnect\Model\GradePointAverage;
      
      /**
       * @Service("grade_point_average_manager")
       */
      class GradePointAverageManager
      {
          /**
           * @var GradePointAverageRepository
           */
          private $gradePointAverageRepository;
      
          /**
           * @var GradePointAveragePaginationFactoryInterface
           */
          private $gradePointAveragePaginationFactory;
      
          /**
           * @var ValidatorInterface
           */
          private $validator;
      
          /**
           * @InjectParams
           *
           * @param GradePointAverageRepository $gradePointAverageRepository
           * @param GradePointAveragePaginationFactoryInterface $gradePointAveragePaginationFactory
           * @param ValidatorInterface $validator
           */
          public function __construct(
              GradePointAverageRepository $gradePointAverageRepository,
              GradePointAveragePaginationFactoryInterface $gradePointAveragePaginationFactory,
              ValidatorInterface $validator
          )
          {
              $this->gradePointAverageRepository = $gradePointAverageRepository;
              $this->gradePointAveragePaginationFactory = $gradePointAveragePaginationFactory;
              $this->validator = $validator;
          }
      
          /**
           * @PreAuthorize("isAllowedToManageTheGradePointAverage(#gradePointAverage)")
           * @param GradePointAverage $gradePointAverage
           * @throws InvalidArgumentException
           */
          public function save(GradePointAverage $gradePointAverage)
          {
              $violationList = $this->validator->validate($gradePointAverage);
              if ($violationList->count()) {
                  throw new InvalidArgumentException;
              }
      
              $this->gradePointAverageRepository->save($gradePointAverage);
          }
      }
      
      GradePointAverageController.php
      <?php
      namespace LGSConnect\Controller;
      
      use Symfony\Component\HttpFoundation\Request;
      use Symfony\Component\HttpFoundation\Response;
      use Symfony\Component\HttpKernel\Log\LoggerInterface;
      use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
      use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
      use Doctrine\Common\Collections\ArrayCollection;
      use FOS\RestBundle\View\View;
      use JMS\DiExtraBundle\Annotation\Service;
      use JMS\DiExtraBundle\Annotation\InjectParams;
      use JMS\SecurityExtraBundle\Annotation\PreAuthorize;
      use Knp\Component\Pager\Pagination\PaginationInterface;
      use LGSConnect\Manager\GradePointAverageManager;
      use LGSConnect\Model\GradePointAverage;
      use LGSConnect\Model\GradePointAverage\AssessmentValue;
      
      /**
       * @Service("grade_point_average_controller", parent="lgs.controller.abstract")
       * @Route("/gpa", service="grade_point_average_controller")
       */
      class GradePointAverageController extends BaseController
      {
          /**
           * @var GradePointAverageManager
           */
          private $gradePointAverageManager;
      
          private $logger;
      
          /**
           * @InjectParams
           *
           * @param GradePointAverageManager $gradePointAverageManager
           * @param LoggerInterface $logger
           */
          public function __construct(GradePointAverageManager $gradePointAverageManager, LoggerInterface $logger)
          {
              $this->gradePointAverageManager = $gradePointAverageManager;
              $this->logger = $logger;
          }
          
          // ...
      
          /**
           * @Route("/{id}", name="gpa.edit", requirements={"id" = "\d+"})
           * @Method("PUT")
           *
           * @param Request $request
           * @param GradePointAverage $gpa
           * @return View
           */
          public function editAction(Request $request, GradePointAverage $gpa)
          {
              $form = $this->formFactory->createNamed(null, 'gpa', $gpa, [
                  'method' => 'PUT',
              ]);
              $form->handleRequest($request);
      
              foreach ($gpa->getAssessmentValues() as $av) {
                  $this->logger->info('GPA ID PREVALIDATE IN CONTROLLER:'.$gpa->getId());
                  $this->logger->info('PREVALIDATE IN CONTROLLER ASSESSMENT VAL ASSESSMENT ID:'.$av->getAssessment()->getId());
                  $this->logger->info('PREVALIDATE IN CONTROLLER ASSESSMENT VAL POINTS:'.$av->getValue());
              }
      
              /*
              // try reversing the order of the collection to see if that helps
              $assessmentVals = $gpa->getAssessmentValues()->toArray();
              $reversed = array_reverse($assessmentVals);
              $reversedColl = new ArrayCollection($reversed);
              $gpa->setAssessmentValues($reversedColl);
              */
      
              if ($form->isValid()) {
                  foreach ($gpa->getAssessmentValues() as $av) {
                      $this->logger->info('GPA ID PRESAVE IN CONTROLLER:'.$gpa->getId());
                      $this->logger->info('PRESAVE IN CONTROLLER ASSESSMENT VAL ASSESSMENT ID:'.$av->getAssessment()->getId());
                      $this->logger->info('PRESAVE IN CONTROLLER ASSESSMENT VAL POINTS:'.$av->getValue());
                  }
                  $this->gradePointAverageManager->save($gpa);
      
                  return new View($gpa, 204);
              }
      
              return new View($form);
          }
      
          // ...
      }
      
      GradePointAverageType.php
      <?php
      namespace LGSConnect\Form\Type;
      
      use Symfony\Component\Form\AbstractType;
      use Symfony\Component\Form\FormBuilderInterface;
      use JMS\DiExtraBundle\Annotation\FormType;
      
      /**
       * @FormType
       */
      class GradePointAverageType extends AbstractType
      {
          /**
           * @param FormBuilderInterface $builder
           * @param array $options
           */
          public function buildForm(FormBuilderInterface $builder, array $options)
          {
              $builder
                  ->add('name')
                  ->add('courses', 'entity', [
                      'class' => 'Model:Course',
                      'multiple' => true
                  ])
                  ->add('assessmentValues', 'collection', [
                      'type' => 'gpa_assessment_value',
                      'allow_add' => true,
                      'by_reference' => false,
                  ])
              ;
          }
      
          /**
           * @return string
           */
          public function getName()
          {
              return 'gpa';
          }
      }
      
      AssessmentValueType.php
      <?php
      namespace LGSConnect\Form\Type\GradePointAverage;
      
      use Symfony\Component\Form\AbstractType;
      use Symfony\Component\Form\FormBuilderInterface;
      use JMS\DiExtraBundle\Annotation\FormType;
      use Symfony\Component\OptionsResolver\OptionsResolverInterface;
      
      /**
       * @FormType("gpa_assessment_value")
       */
      class AssessmentValueType extends AbstractType
      {
          /**
           * @param FormBuilderInterface $builder
           * @param array $options
           */
          public function buildForm(FormBuilderInterface $builder, array $options)
          {
              $builder
                  ->add('assessment', 'entity', [
                      'class' => 'Model:Assessment',
                  ])
                  ->add('value', 'number', [
                      'precision' => 2,
                  ])
              ;
          }
      
          /**
           * @param OptionsResolverInterface $resolver
           */
          public function setDefaultOptions(OptionsResolverInterface $resolver)
          {
              $resolver->setDefaults([
                  'data_class' => 'LGSConnect\Model\GradePointAverage\AssessmentValue',
              ]);
          }
      
          /**
           * @return string
           */
          public function getName()
          {
              return 'gpa_assessment_value';
          }
      }
      

        Activity

        There are no comments yet on this issue.

          People

          • Assignee:
            Benjamin Eberlei
            Reporter:
            Dylan Johnson
          • Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated: