Adib Aroui
Adib Aroui

Reputation: 5067

How to map Product entity so that it is managed by Doctrine?

I am trying to build a module under PS 1.7.6.1.

In design, I have a manyToOne relationship between a Product and a Preorder (many preorders can be associated to one product).

The Preorder object is an ORM entity:

//mymodule/src/Entity
class Preorder
{
    /**
     * @var int
     *
     * @ORM\Id
     * @ORM\Column(name="id_preorder", type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var int
     *
     * @ORM\Column(name="id_product", type="integer")
     */
    private $productId;

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

    setter and getter
}

In controller:

//src/mymodule/src/Controller


use Doctrine\DBAL\Types\TextType;
use PrestaShopBundle\Controller\Admin\FrameworkBundleAdminController;
use Doctrine\ORM\EntityManagerInterface;
use MyModule\Entity\Preoder;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\HttpFoundation\Request;
use Product;

class PreorderController extends FrameworkBundleAdminController
{
public function createAction(Request $request){

        $preorder = new Preorder();
        $preorderForm = $this->createFormBuilder($preorder)
                ->add('email', EmailType::class)
                ->add('productId', EntityType::class, [
                    'class' => Product::class,
                ])
                ->getForm();

        $bookingForm->handleRequest($request);

// validate and persist
}}

The problem is that the form builder doesn't recognize the Product entity. It throws a runtime exception:

Class "Product" seems not to be a managed Doctrine entity. Did you forget to map it?

I can't find in the core files an example where such a scenario is handled. Thank you very much in advance for guiding/helping me the resolve this issue.

Upvotes: 0

Views: 865

Answers (1)

Pierrick Rambaud
Pierrick Rambaud

Reputation: 2400

The main issue is that product_id is not an entity so there is 0 chance that The formbuilder handle it with the EntityType::class. you need to properly define (as explained in the doc) your ManyToOne relation with objects

on the product side :

/**
 * @ORM\Entity(repositoryClass="App\Repository\ProductRepository")
 */
class Product
{
    // usual stuff

    /**
     * @ORM\ManyToOne(targetEntity="App\Entity\User", inversedBy="product", cascade={"persist"})
     */
    private $preorders;
}

and on the preorder side:

/**
 * @ORM\Entity(repositoryClass="App\Repository\ProductRepository")
 */
class Product
{
    // usual stuff

    /**
     * @ORM\OneToMany(targetEntity="App\Entity\Product", mappedBy="preorders")
     */
    private $product;
}

In your formBuilder, product will be an entity and recognize by as such by the EntityType::class

EDIT

If your product is a legacy class unmapped by the ORM then you can use the dataTransformer to help your formBuilder recognize the legacy entity.

namespace App\DataTransformer;

class ProductToIdTransformer implements DataTransformerInterface
{
    public function transform($product)
    {
        if (null === $product) {
            return '';
        }

        return $product->getId();
    }

    public function reverseTransform($product_id)
    {
        if (!$product_id){
            return;
        } 

        //your db logic to retrieve the product

        if (null === $field){
            throw new TransformationFailedException(sprintf("the product '%s' does not exist!", $product_id));
        }

        return $product;

    }
}

Then in your formbuilder you'll use a CollectionType instead:

$preorderForm = $this->createFormBuilder($preorder)
    ->add('email', EmailType::class)
    ->add('product', CollectionType::class, [
        'class' => Product::class,
        //some logic to adapt the different choices to your needs
    ])
;

$preorderForm
    ->get('product')
    ->addModelTransformer(ProductToIdTransformer::class)
;

$preorderForm = $preorderForm->getForm();

Upvotes: 1

Related Questions