fzaninotto / Faker

Faker is a PHP library that generates fake data for you
MIT License
26.8k stars 3.57k forks source link

Doctrine entity populator type error #2010

Open ScottA38 opened 4 years ago

ScottA38 commented 4 years ago

Summary

Cannot use Doctrine EntityManager with ORM EntityManager

Versions

Version
PHP 7.4.4
fzaninotto/faker 1.9.0

Self-enclosed code snippet for reproduction

<?php

declare(strict_types=1);

namespace WebApp\Util;

use Doctrine\ORM\EntityManager;
use Faker\ORM\Doctrine\Populator;
use Faker\Factory;
use WebApp\Models\Product;
use Faker\Generator;

class ProductPopulator
{
    private EntityManager $em;
    private Generator $generator;

    public function __construct(EntityManager $em)
    {
        $this->em = $em;
        $this->generator = Factory::create();
    }

    private function getspecialInstructions()
    {
        $nameReducer = function ($carry, $lChar) {
            if (!in_array($lChar, ["a", "e", "i", "o", "u"])) {
                $carry++;
            }
            return $carry;
        };
        return [
            'price' => function () {
                return $this->generator->randomFloat(2, 0, 10000);
            },
            'name' => function () use ($nameReducer) {
                $name = $this->generator->unique()->company;
                while (array_reduce(str_split(strtolower($name)), $nameReducer) < 3) {
                    $name = $this->generator->unique()->company;
                }
                return $name;
            },
            'dimensions' => function () {
                return [
                    $this->generator->randomNumber(3),
                    $this->generator->randomNumber(3),
                    $this->generator->randomNumber(3)
                ];
            }
        ];
    }

    public function getEntityManager(): EntityManager
    {
        return $this->em;
    }

    /**
     * Populate the database with a given amount of DBAL entity. Returns PK of each popluated element
     * @param Product $entity
     * @param int $amount
     * @return array
     */
    public function populate(string $className, int $amount)
    {
        $metadata = $this->em->getClassMetadata($className);
        $fieldNames = array_keys($metadata->fieldMappings);
        $specialInstructions = $this->getspecialInstructions();
        $instructionKeys = array_keys($specialInstructions);
        foreach ($instructionKeys as &$instructionKey) {
            if (!in_array($instructionKey, $fieldNames)) {
                unset($specialInstructions[$instructionKey]);
            }
        }
        $populator = new Populator($this->generator, null, 1);
        $populator->addEntity($className, $amount, $specialInstructions, [], false);
        return $populator->execute();
    }
}

Expected output

SELECT * FROM Furniture

records display

Actual output

>>> main()
$pop = new ProductPopulator($em);
$pop->populate('WebApp\models\Furniture', 1);
>>> error output (from PHPUnit tests)
TypeError: Argument 2 passed to Faker\ORM\Doctrine\Populator::__construct() must be an instance of Doctrine\Common\Persistence\ObjectManager or null, instance of Doctrine\ORM\EntityManager given, called in /Users/ScottAnderson/Documents/Tech/commissions/shopping_app_test/src/Util/ProductPopulator.php on line 76
ScottA38 commented 4 years ago

To anyone who encounters this, this is a doctrine version issue (maybe it will be patched in a future minor release, I don't know).

The specific minimum version of doctrine/orm that seems to be compatible with Faker at the time of writing is 2.7.2, 2.7.3 will break it as shown in the original error report.

So constrain your composer version as so:

"require": {
        "doctrine/orm": "2.7.2"
    },