简体   繁体   中英

Adding references to a Document from controller without previously querying the DB (Symfony/Doctrine MongoDB)

I've already searched on StackOverflow and read the corresponding chapters of the Doctrine documentation ( http://docs.doctrine-project.org/projects/doctrine-mongodb-odm/en/latest/index.html ) but can't find what I'm looking for.

I'm working on an API made with Symfony v2.8, using Doctrine MongoDB v1.1 and a MongoDB v3.0.14 database.

I have two differents Documents: "Spot" and "Feature". A "Spot" contains a collection of document "Feature", with a ReferenceMany relation:

// Spot document declaration

/**
 * @var \Transversal\SessionBundle\Document\Feature
 * @MongoDB\ReferenceMany(strategy="set", targetDocument="Transversal\SessionBundle\Document\Feature", sort={"uploadDate"="asc"})
 * @Serializer\Expose
 */
protected $features = array();

I'm working on the Spot creation route/controller, where I need to send the Spot name, description and the list of existing Features I want to add to the spot.

What I'm doing for now is sending the name, the description and an array of Feature ids in the body of the request. Then, in the controller, I loop through this array, and for each id I:

  • Get an instance of the Feature from the db via its id (so it's one db request per iteration)
  • Add it to the Spot object via my $spot->addFeature() method

Then I persist and flush to save the newly created spot. Here is the code of my controller method (I modified the code to make it more readable):

 * @Rest\Post("")
   * @return \Symfony\Component\HttpFoundation\JsonResponse
   * @throws BosHttpException
   */
  public function createAction()
  {
    $spot = new Spot();
    $request = $this->getCurrentRequest();

    // retrieve the name and description for the new spot here
    $form = $this->createForm(SpotType::class, $spot);
    $form->handleRequest($request);

    $content = $request->getContent();
    $params = "";
    if (!empty($content)) {
      $params = json_decode($content, true);
    }

    $document_manager = $this->getDocumentManager();
    $featureIds = $params['featureIds'];
    foreach ($featuresIds as $featureId) {
      $feature = $document_manager->find('Transversal\SessionBundle\Document\Feature', $featureId);
      $spot->addFeature($feature);
    }

    $document_manager = $this->getDocumentManager();
    $document_manager->persist($spot);
    $document_manager->flush();

    return $this->getOutputView("Spot creation - succeed", Codes::HTTP_CREATED, $this->formatResponse(null, true));

  }

Here is the code of addFeature() in the Spot.php file:

/**
 * Add feature
 *
 * @param \Transversal\SessionBundle\Document\Feature $feature
 */
public function addFeature(\Transversal\SessionBundle\Document\Feature $feature)
{
    $this->features[] = $feature;
}

It means that if I have an array of 20 Feature's id, my foreach loop will request 20 times my db and I know it's not a viable solution (I know I probably can use a single request to get them all but this is not what I'm looking for).

Is there a way to assign the Features to the Spot without having to generate instances of them and requesting my db, knowing that there are references ?

Thanks in advance for your help!

This is an example of how you could use @ParamConverter to pass just the id of the $feature and not the object

use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;

/**
 * @ParamConverter("feature", class="YourBundle:Feature")
 */
public function addFeature(\Transversal\SessionBundle\Document\Feature $feature){
  $this->features[] = $feature;
}

Which means that if you let the code like this

foreach($featuresIds as $featureId) {  
  $spot->addFeature($featureId);
}

will work as well because doctrine should recognize that the id that you are passing as parameter is the id of the 'Feature' entity. Anyway the ORM is doing a query to get the object too, you can try and compare times.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM