Orm: Not detected new mapped field

Created on 28 Oct 2019  路  19Comments  路  Source: doctrine/orm

Bug Report

| Q | A
|------------ | ------
| BC Break | no
| Version | 2.4

Summary

I tried to map a field exactly as the same as one another in my entity, when running:

php bin/console doctrine:schema:update --dump-sql
or
php bin/console doctrine:schema:update --force
i got this: [OK] Nothing to update - your database is already in sync with the current entity metadata.
And the field is fine in the database:
image

Te field is "promoted", same as "certified", same behavior expected.

Current behavior

In practice, whenever i try to work with the field "promoted" the same way as i do with the field "certified", it says there's no mapped field "promoted".

How to reproduce

BaseListing.php:

<?php

/*
 * This file is part of the Cocorico package.
 *
 * (c) Cocolabs SAS <[email protected]>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Cocorico\ListingBundle\Model;

use Cocorico\ListingBundle\Entity\Listing;
use Cocorico\ListingBundle\Validator\Constraints as CocoricoAssert;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * Listing
 *
 * @CocoricoAssert\ListingConstraint()
 *
 * @ORM\MappedSuperclass
 */
abstract class BaseListing
{

    /* Status */
    const STATUS_NEW = 1;
    const STATUS_PUBLISHED = 2;
    const STATUS_INVALIDATED = 3;
    const STATUS_SUSPENDED = 4;
    const STATUS_DELETED = 5;
    const STATUS_TO_VALIDATE = 6;

    public static $statusValues = array(
        self::STATUS_NEW => 'entity.listing.status.new',
        self::STATUS_PUBLISHED => 'entity.listing.status.published',
        self::STATUS_INVALIDATED => 'entity.listing.status.invalidated',
        self::STATUS_SUSPENDED => 'entity.listing.status.suspended',
        self::STATUS_DELETED => 'entity.listing.status.deleted',
        self::STATUS_TO_VALIDATE => 'entity.listing.status.to_validate',
    );

    public static $visibleStatus = array(
        self::STATUS_NEW,
        self::STATUS_PUBLISHED,
        self::STATUS_INVALIDATED,
        self::STATUS_SUSPENDED,
        self::STATUS_TO_VALIDATE,
    );


    /* Type */
    const TYPE_ONE = 1;
    const TYPE_TWO = 2;
    const TYPE_THREE = 3;

    public static $typeValues = array(
        self::TYPE_ONE => 'entity.listing.type.one',
        self::TYPE_TWO => 'entity.listing.type.two',
        self::TYPE_THREE => 'entity.listing.type.three',
    );

    /* Cancellation policy */
    const CANCELLATION_POLICY_FLEXIBLE = 1;
    const CANCELLATION_POLICY_STRICT = 2;

    public static $cancellationPolicyValues = array(
        self::CANCELLATION_POLICY_FLEXIBLE => 'entity.listing.cancellation_policy.flexible',
        self::CANCELLATION_POLICY_STRICT => 'entity.listing.cancellation_policy.strict',
    );

    public static $cancellationPolicyDescriptions = array(
        self::CANCELLATION_POLICY_FLEXIBLE => 'entity.listing.cancellation_policy_desc.flexible',
        self::CANCELLATION_POLICY_STRICT => 'entity.listing.cancellation_policy_desc.strict',
    );

    /**
     * @ORM\Column(name="status", type="smallint", nullable=false)
     *
     * @var integer
     */
    protected $status = self::STATUS_NEW;

    /**
     * @ORM\Column(name="type", type="smallint", nullable=true)
     *
     * @var integer
     */
    protected $type;

    /**
     * @ORM\Column(name="price", type="decimal", precision=8, scale=0, nullable=false)
     * @Assert\NotBlank(message="assert.not_blank")
     *
     * @var integer
     */
    protected $price = 0;

    /**
     * 
     * @ORM\Column(name="certified", type="boolean", nullable=true)
     *
     * @var boolean
     */
    protected $certified;

    /**
     * 
     *
     * @ORM\Column(name="promoted", type="boolean", nullable=true)
     * 
     * @var boolean
     */
    protected $promoted;


    /**
     *
     * @ORM\Column(name="min_duration", type="smallint", nullable=true)
     *
     * @var integer
     */
    protected $minDuration;

    /**
     *
     * @ORM\Column(name="max_duration", type="smallint", nullable=true)
     *
     * @var integer
     */
    protected $maxDuration;

    /**
     *
     * @ORM\Column(name="cancellation_policy", type="smallint", nullable=false)
     * @Assert\NotBlank(message="assert.not_blank")
     *
     * @var integer
     */
    protected $cancellationPolicy = self::CANCELLATION_POLICY_FLEXIBLE;


    /**
     * @ORM\Column(name="average_rating", type="smallint", nullable=true)
     *
     * @var integer
     */
    protected $averageRating;

    /**
     * @ORM\Column(name="comment_count", type="integer", nullable=true)
     *
     * @var integer
     */
    protected $commentCount = 0;

    /**
     * Admin notation
     *
     * @ORM\Column(name="admin_notation", type="decimal", precision=3, scale=1, nullable=true)
     *
     * @var float
     */
    protected $adminNotation;

    /**
     * @ORM\Column(name="availabilities_updated_at", type="datetime", nullable=true)
     *
     * @var \DateTime
     */
    protected $availabilitiesUpdatedAt;

    /**
     * Translation proxy
     *
     * @param $method
     * @param $arguments
     * @return mixed
     */
    public function __call($method, $arguments)
    {
        return $this->proxyCurrentLocaleTranslation($method, $arguments);
    }

    /**
     * Set status
     *
     * @param  integer $status
     * @return $this
     */
    public function setStatus($status)
    {
        if (!in_array($status, array_keys(self::$statusValues))) {
            throw new \InvalidArgumentException(
                sprintf('Invalid value for listing.status : %s.', $status)
            );
        }

        $this->status = $status;

        return $this;
    }

    /**
     * Get status
     *
     * @return integer
     */
    public function getStatus()
    {
        return $this->status;
    }

    /**
     * Get Status Text
     *
     * @return string
     */
    public function getStatusText()
    {
        return self::$statusValues[$this->getStatus()];
    }

    /**
     * Return available status for current status
     *
     * @param int $status
     *
     * @return array
     */
    public static function getAvailableStatusValues($status)
    {
        $availableStatus = array(self::STATUS_DELETED);

        if ($status == self::STATUS_NEW) {
            $availableStatus[] = self::STATUS_PUBLISHED;
        } elseif ($status == self::STATUS_PUBLISHED) {
            $availableStatus[] = self::STATUS_SUSPENDED;
        } elseif ($status == self::STATUS_INVALIDATED) {
            $availableStatus[] = self::STATUS_TO_VALIDATE;
        } elseif ($status == self::STATUS_SUSPENDED) {
            $availableStatus[] = self::STATUS_PUBLISHED;
        }

        //Prepend current status to visible status
        array_unshift($availableStatus, $status);

        //Construct associative array with keys equals to status values and values to label of status
        $status = array_intersect_key(
            self::$statusValues,
            array_flip($availableStatus)
        );

        return $status;
    }


    /**
     * Set price
     *
     * @param  integer $price
     * @return $this
     */
    public function setPrice($price)
    {
        $this->price = $price;

        return $this;
    }

    /**
     * Get price
     *
     * @return string
     */
    public function getPrice()
    {
        return $this->price;
    }

    /**
     * Get price
     *
     * @return float
     */
    public function getPriceDecimal()
    {
        return $this->price / 100;
    }

    /**
     * Get offerer amount fees
     *
     * @param array $feeAsOfferer
     *
     * @return float
     */
    public function getAmountFeeAsOffererDecimal($feeAsOfferer)
    {
        return $this->getPriceDecimal() * $feeAsOfferer['percent'] + $feeAsOfferer['fixed'] / 100;
    }

    /**
     * Get amount to pay to offerer
     *
     * @param array $feeAsOfferer
     *
     * @return float
     */
    public function getAmountToPayToOffererDecimal($feeAsOfferer)
    {
        return $this->getPriceDecimal() - $this->getAmountFeeAsOffererDecimal($feeAsOfferer);
    }

    /**
     * Get amount to pay to offerer minus VAT when listing price is VAT excluded.
     *
     * Return the same result than getAmountToPayToOffererDecimal used with listing price VAT is included:
     * amountToPayVATIncluded = PriceVATIncluded - (PriceVATIncluded * feeAsOfferer)
     * amountToPayVATExcluded = amountToPayVATIncluded / (1 + vatRate)
     *
     * So :
     * amountToPayVATIncluded = ((price * (1 + vatRate)) - (price * (1 + vatRate) * feeAsOfferer))
     * amountToPayVATExcluded = amountToPayVATIncluded / (1 + vatRate)
     * amountToPayVATExcluded = price - price * feeAsOfferer
     * amountToPayVATExcluded = getAmountToPayToOffererDecimal
     *
     *
     * @param array $feeAsOfferer
     *
     * @return int
     */
    public function amountToPayToOffererForPriceExcludingVATDecimal($feeAsOfferer)
    {
        return $this->getAmountToPayToOffererDecimal($feeAsOfferer);
    }

    /**
     * Get offerer amount fees when listing price is VAT excluded.
     * Fees are computed on listing price VAT included
     *
     * @param array $feeAsOfferer
     * @param float $vatRate
     *
     * @return int
     */
    public function getAmountFeeAsOffererForPriceExcludingVATDecimal($feeAsOfferer, $vatRate)
    {
        return $this->getAmountFeeAsOffererDecimal($feeAsOfferer) * (1 + $vatRate);
    }

    /**
     * Return the min listing price according to offerer fees and default min price.
     *
     * @param array $defaultFeeAsOfferer
     * @param int   $defaultMinPrice
     * @return float
     */
    public function getMinPrice($defaultFeeAsOfferer, $defaultMinPrice)
    {
        $result = $defaultMinPrice;
        /** @var  $this Listing */
        $user = $this->getUser();
        if ($user) {
            $feeAsOfferer = $user->getFeeAsOfferer($defaultFeeAsOfferer);
            $result = max(round($feeAsOfferer['fixed'] / (1 - $feeAsOfferer['percent']), 2), $defaultMinPrice);
        }

        return $result;
    }


    /**
     * @param array $defaultFeeAsOfferer
     * @param int   $defaultMinPrice
     * @return float
     */
    public function getMinPriceDecimal($defaultFeeAsOfferer, $defaultMinPrice)
    {
        return $this->getMinPrice($defaultFeeAsOfferer, $defaultMinPrice) / 100;
    }

    /**
     * Check if listing has correct min price according to offerer fees and default min price
     *
     * @param array $defaultFeeAsOfferer
     * @param int   $defaultMinPrice
     * @return bool
     */
    public function hasMinPrice($defaultFeeAsOfferer, $defaultMinPrice)
    {
        if ($defaultMinPrice > 0 || $this->getPrice() > 0) {//if listing is not free or min price > 0
            $minPrice = $this->getMinPrice($defaultFeeAsOfferer, $defaultMinPrice);

            if ($this->getPrice() < $minPrice) {
                return false;
            }
        }

        //else listing is free

        return true;
    }

    /**
     * @return boolean
     */
    public function isCertified()
    {
        return $this->certified;
    }

    /**
     * @param boolean $certified
     */
    public function setCertified($certified)
    {
        $this->certified = $certified;
    }

    /**
     * @return boolean
     */
    public function isPromoted()
    {
        return $this->promoted;
    }

    /**
     * @param boolean $promoted
     */
    public function setPromoted($promoted)
    {
        $this->promoted = $promoted;
    }

    /**
     * @return int
     */
    public function getType()
    {
        return $this->type;
    }

    /**
     * Set type
     *
     * @param  integer $type
     * @return $this
     */
    public function setType($type)
    {
        if (!in_array($type, array_keys(self::$typeValues))) {
            throw new \InvalidArgumentException(
                sprintf('Invalid value for listing.type : %s.', $type)
            );
        }

        $this->type = $type;

        return $this;
    }

    /**
     * Get Type Text
     *
     * @return string
     */
    public function getTypeText()
    {
        return self::$typeValues[$this->getType()];
    }

    /**
     * Get certified
     *
     * @return boolean
     */
    public function getCertified()
    {
        return $this->certified;
    }

    /**
     * Get promoted
     *
     * @return boolean
     */
    public function getPromoted()
    {
        return $this->promoted;
    }

    /**
     * @return int
     */
    public function getMinDuration()
    {
        return $this->minDuration;
    }

    /**
     * @param int $minDuration
     */
    public function setMinDuration($minDuration)
    {
        $this->minDuration = $minDuration;
    }

    /**
     * @return int
     */
    public function getMaxDuration()
    {
        return $this->maxDuration;
    }

    /**
     * @param int $maxDuration
     */
    public function setMaxDuration($maxDuration)
    {
        $this->maxDuration = $maxDuration;
    }

    /**
     * @return int
     */
    public function getCancellationPolicy()
    {
        return $this->cancellationPolicy;
    }

    /**
     * @param int $cancellationPolicy
     *
     * @return BaseListing
     */
    public function setCancellationPolicy($cancellationPolicy)
    {
        if (!in_array($cancellationPolicy, array_keys(self::$cancellationPolicyValues))) {
            throw new \InvalidArgumentException(
                sprintf('Invalid value for listing.status : %s.', $cancellationPolicy)
            );
            //$cancellationPolicy = self::CANCELLATION_POLICY_FLEXIBLE;
        }

        $this->cancellationPolicy = $cancellationPolicy;

        return $this;
    }

    /**
     * Get Cancellation Policy Text
     *
     * @return string
     */
    public function getCancellationPolicyText()
    {
        return self::$cancellationPolicyValues[$this->getCancellationPolicy()];
    }

    /**
     * Get Cancellation Policy Description
     *
     * @return string
     */
    public function getCancellationPolicyDescription()
    {
        return self::$cancellationPolicyDescriptions[$this->getCancellationPolicy()];
    }

    /**
     * Set averageRating
     *
     * @param  integer $averageRating
     * @return $this
     */
    public function setAverageRating($averageRating)
    {
        $this->averageRating = $averageRating;

        return $this;
    }

    /**
     * Get averageRating
     *1
     *
     * @return integer
     */
    public function getAverageRating()
    {
        return $this->averageRating;
    }

    /**
     * Set commentCount
     *
     * @param  integer $commentCount
     * @return $this
     */
    public function setCommentCount($commentCount)
    {
        $this->commentCount = $commentCount;

        return $this;
    }

    /**
     * Get commentCount
     *1
     *
     * @return integer
     */
    public function getCommentCount()
    {
        return $this->commentCount;
    }

    /**
     * @return float
     */
    public function getAdminNotation()
    {
        return $this->adminNotation;
    }

    /**
     * @param float $adminNotation
     */
    public function setAdminNotation($adminNotation)
    {
        $this->adminNotation = $adminNotation;
    }


    /**
     * @return \DateTime
     */
    public function getAvailabilitiesUpdatedAt()
    {
        return $this->availabilitiesUpdatedAt;
    }

    /**
     * @param \DateTime $availabilitiesUpdatedAt
     */
    public function setAvailabilitiesUpdatedAt($availabilitiesUpdatedAt)
    {
        $this->availabilitiesUpdatedAt = $availabilitiesUpdatedAt;
    }

    /**
     * @return bool
     */
    public function hasPrice()
    {
        return $this->getPrice() > 0;
    }
}`

Entity\Listing.php:

`<?php

namespace Cocorico\ListingBundle\Entity;

use Cocorico\BookingBundle\Entity\Booking;
use Cocorico\ListingBundle\Model\BaseListing;
use Cocorico\ListingBundle\Model\ListingOptionInterface;
use Cocorico\ListingCategoryBundle\Entity\ListingListingCategory;
use Cocorico\ListingCharacteristicBundle\Entity\ListingListingCharacteristic;
use Cocorico\ListingDiscountBundle\Entity\ListingDiscount;
use Cocorico\ListingImageBundle\Entity\ListingImage;
use Cocorico\ListingLocationBundle\Entity\ListingLocation;
use Cocorico\MessageBundle\Entity\Thread;
use Cocorico\UserBundle\Entity\User;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use Knp\DoctrineBehaviors\Model as ORMBehaviors;
use Symfony\Component\Validator\Constraints as Assert;


/**
 * Listing
 *
 * @ORM\Entity(repositoryClass="Cocorico\ListingBundle\Repository\ListingRepository")
 *
 * @ORM\Table(name="listing",indexes={
 *    @ORM\Index(name="created_at_l_idx", columns={"created_at"}),
 *    @ORM\Index(name="status_l_idx", columns={"status"}),
 *    @ORM\Index(name="price_idx", columns={"price"}),
 *    @ORM\Index(name="type_idx", columns={"type"}),
 *    @ORM\Index(name="min_duration_idx", columns={"min_duration"}),
 *    @ORM\Index(name="max_duration_idx", columns={"max_duration"}),
 *    @ORM\Index(name="average_rating_idx", columns={"average_rating"}),
 *    @ORM\Index(name="admin_notation_idx", columns={"admin_notation"}),
 *    @ORM\Index(name="platform_notation_idx", columns={"platform_notation"}),
 *  })
 */
class Listing extends BaseListing
{
    use ORMBehaviors\Timestampable\Timestampable;
    use ORMBehaviors\Translatable\Translatable;

    use \Cocorico\ListingSearchAdvancedBundle\Model\ListingSearchableTrait;
//    use \Cocorico\ListingCategoryFieldBundle\Model\ListingCategoryFieldableTrait;
//    use \Cocorico\DeliveryBundle\Model\ListingDeliverableTrait;
//    use \Cocorico\ListingDepositBundle\Model\ListingDepositableTrait;
//    use \Cocorico\ListingSessionBundle\Model\ListingSessionableTrait;

//    use \Cocorico\ServiceBundle\Model\ListingTrait;
//    use \Cocorico\ListingVideoBundle\Model\ListingVideoTrait;
//    use \Cocorico\CarrierBundle\Model\ListingCarrierableTrait;

    /**
     * @ORM\Id
     * @ORM\Column(name="id", type="integer", nullable=false)
     * @ORM\GeneratedValue(strategy="CUSTOM")
     * @ORM\CustomIdGenerator(class="Cocorico\CoreBundle\Model\CustomIdGenerator")
     *
     * @var integer
     */
    protected $id;

    /**
     * @Assert\NotBlank(message="assert.not_blank")
     *
     * @ORM\ManyToOne(targetEntity="Cocorico\UserBundle\Entity\User", inversedBy="listings", cascade={"persist"})
     * @ORM\JoinColumn(name="user_id", referencedColumnName="id", nullable=false, onDelete="CASCADE")
     *
     * @var User
     */
    protected $user;

    /**
     * @ORM\OneToOne(targetEntity="Cocorico\ListingLocationBundle\Entity\ListingLocation", inversedBy="listing", cascade={"persist", "remove"}, orphanRemoval=true)
     * @ORM\JoinColumn(name="location_id", referencedColumnName="id", onDelete="CASCADE")
     *
     * @var ListingLocation
     **/
    protected $location;

    /**
     * @ORM\OneToMany(targetEntity="Cocorico\ListingCategoryBundle\Entity\ListingListingCategory", mappedBy="listing", cascade={"persist", "remove"}, orphanRemoval=true)//, fetch="EAGER"
     *
     */
    protected $listingListingCategories;

    /**
     * For Asserts @see \Cocorico\ListingBundle\Validator\Constraints\ListingValidator
     *
     * @ORM\OneToMany(targetEntity="Cocorico\ListingImageBundle\Entity\ListingImage", mappedBy="listing", cascade={"persist", "remove"}, orphanRemoval=true)
     * @ORM\OrderBy({"position" = "asc"})
     */
    protected $images;

    /**
     * @ORM\OneToMany(targetEntity="Cocorico\ListingCharacteristicBundle\Entity\ListingListingCharacteristic", mappedBy="listing", cascade={"persist", "remove"}, orphanRemoval=true) //, fetch="EAGER"
     *
     */
    protected $listingListingCharacteristics;

    /**
     *
     * @ORM\OneToMany(targetEntity="Cocorico\ListingDiscountBundle\Entity\ListingDiscount", mappedBy="listing", cascade={"persist", "remove"}, orphanRemoval=true)
     * @ORM\OrderBy({"fromQuantity" = "asc"})
     */
    protected $discounts;


    /**
     * @ORM\OneToMany(targetEntity="Cocorico\BookingBundle\Entity\Booking", mappedBy="listing", cascade={"persist", "remove"}, orphanRemoval=true)
     * @ORM\OrderBy({"createdAt" = "desc"})
     */
    protected $bookings;

    /**
     * @ORM\OneToMany(targetEntity="Cocorico\MessageBundle\Entity\Thread", mappedBy="listing", cascade={"remove"}, orphanRemoval=true)
     * @ORM\OrderBy({"createdAt" = "desc"})
     */
    protected $threads;

    /**
     *
     * @ORM\OneToMany(targetEntity="Cocorico\ListingBundle\Model\ListingOptionInterface", mappedBy="listing", cascade={"persist", "remove"}, orphanRemoval=true)
     */
    protected $options;


    public function __construct()
    {
        $this->images = new ArrayCollection();
        $this->listingListingCharacteristics = new ArrayCollection();
        $this->listingListingCategories = new ArrayCollection();
        $this->discounts = new ArrayCollection();
        $this->bookings = new ArrayCollection();
        $this->threads = new ArrayCollection();
        $this->options = new ArrayCollection();
    }


    /**
     * Get id
     *
     * @return integer
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Add characteristics
     *
     * @param  ListingListingCharacteristic $listingListingCharacteristic
     * @return Listing
     */
    public function addListingListingCharacteristic(ListingListingCharacteristic $listingListingCharacteristic)
    {
        $this->listingListingCharacteristics[] = $listingListingCharacteristic;

        return $this;
    }


    /**
     * Remove characteristics
     *
     * @param ListingListingCharacteristic $listingListingCharacteristic
     */
    public function removeListingListingCharacteristic(ListingListingCharacteristic $listingListingCharacteristic)
    {
        $this->listingListingCharacteristics->removeElement($listingListingCharacteristic);
        $listingListingCharacteristic->setListing(null);
    }

    /**
     * Get characteristics
     *
     * @return \Doctrine\Common\Collections\Collection|ListingListingCharacteristic[]
     */
    public function getListingListingCharacteristics()
    {
        return $this->listingListingCharacteristics;
    }

    /**
     * Get characteristics ordered by Group and Characteristic
     *
     * @return ArrayCollection
     */
    public function getListingListingCharacteristicsOrderedByGroup()
    {
        $iterator = $this->listingListingCharacteristics->getIterator();
        $iterator->uasort(
            function ($a, $b) {
                /**
                 * @var ListingListingCharacteristic $a
                 * @var ListingListingCharacteristic $b
                 */
                $groupPosA = $a->getListingCharacteristic()->getListingCharacteristicGroup()->getPosition();
                $groupPosB = $b->getListingCharacteristic()->getListingCharacteristicGroup()->getPosition();

                $characteristicPosA = $a->getListingCharacteristic()->getPosition();
                $characteristicPosB = $b->getListingCharacteristic()->getPosition();
                if ($groupPosA == $groupPosB) {
                    if ($characteristicPosA == $characteristicPosB) {
                        return 0;
                    }

                    return ($characteristicPosA < $characteristicPosB) ? -1 : 1;
                }

                return ($groupPosA < $groupPosB) ? -1 : 1;
            }
        );

        return new ArrayCollection(iterator_to_array($iterator));
    }

    /**
     * Add characteristics
     *
     * @param  ListingListingCharacteristic $listingListingCharacteristic
     * @return Listing
     */
    public function addListingListingCharacteristicsOrderedByGroup(
        ListingListingCharacteristic $listingListingCharacteristic
    ) {
        return $this->addListingListingCharacteristic($listingListingCharacteristic);
    }


    /**
     * Remove characteristics
     *
     * @param ListingListingCharacteristic $listingListingCharacteristic
     */
    public function removeListingListingCharacteristicsOrderedByGroup(
        ListingListingCharacteristic $listingListingCharacteristic
    ) {
        $this->removeListingListingCharacteristic($listingListingCharacteristic);
    }


    /**
     * Add category
     *
     * @param  ListingListingCategory $listingListingCategory
     * @return Listing
     */
    public function addListingListingCategory(ListingListingCategory $listingListingCategory)
    {
        $listingListingCategory->setListing($this);
        $this->listingListingCategories[] = $listingListingCategory;

        return $this;
    }


    /**
     * Remove category
     *
     * @param ListingListingCategory $listingListingCategory
     */
    public function removeListingListingCategory(ListingListingCategory $listingListingCategory)
    {
//        foreach ($listingListingCategory->getValues() as $value) {
//            $listingListingCategory->removeValue($value);
//        }

        $this->listingListingCategories->removeElement($listingListingCategory);
    }

    /**
     * Get categories
     *
     * @return \Doctrine\Common\Collections\Collection|ListingListingCategory[]
     */
    public function getListingListingCategories()
    {
        return $this->listingListingCategories;
    }


    /**
     * Set user
     *
     * @param  \Cocorico\UserBundle\Entity\User $user
     * @return Listing
     */
    public function setUser(User $user = null)
    {
        $this->user = $user;

        return $this;
    }

    /**
     * Get user
     *
     * @return \Cocorico\UserBundle\Entity\User
     */
    public function getUser()
    {
        return $this->user;
    }

}

Expected behavior

I excepted doctrine to query for "promoted" the same way as "certified", instead, it says it is'nt mapped, for more info, here's my post on stack overflow: https://stackoverflow.com/questions/58504171/why-isnt-my-property-mapped-to-the-entity

Missing Tests Question

Most helpful comment

Thanks for the help it's now resolved after upgrading some dependencies and clearing caches it works great thanks again for the help!

All 19 comments

Sorry for the code blocks, it doesnt work..

Did you perhaps have a typo in the version you're using? If not, is this reproducible on the latest version of the ORM (v2.6.4)? v2.4 is pretty much ancient and no longer maintained.

Did you perhaps have a typo in the version you're using? If not, is this reproducible on the latest version of the ORM (v2.6.4)? v2.4 is pretty much ancient and no longer maintained.

hey thanks, i got this in my composer.lock: "doctrine/orm": "^2.5",

The composer show command grep doctrine give me this:

image

I also got this composer.json here in vendor/sonata-project/admin-bundle/composer.json:

{
"name": "sonata-project/admin-bundle",
"type": "symfony-bundle",
"description": "The missing Symfony Admin Generator",
"keywords": [
"Admin Generator",
"admin",
"sonata",
"bootstrap"
],
"homepage": "https://sonata-project.org/bundles/admin",
"license": "MIT",
"authors": [
{
"name": "Thomas Rabaix",
"email": "thomas.[email protected]",
"homepage": "https://sonata-project.org"
},
{
"name": "Sonata Community",
"homepage": "https://github.com/sonata-project/SonataAdminBundle/contributors"
}
],
"require": {
"php": "^5.6 || ^7.0",
"doctrine/common": "^2.7",
"doctrine/inflector": "^1.1",
"knplabs/knp-menu-bundle": "^2.2",
"sonata-project/block-bundle": "^3.11",
"sonata-project/core-bundle": "^3.9",
"sonata-project/exporter": "^1.8",
"symfony/asset": "^2.8 || ^3.2 || ^4.0",
"symfony/config": "^2.8 || ^3.2 || ^4.0",
"symfony/console": "^2.8 || ^3.2 || ^4.0",
"symfony/dependency-injection": "^2.8 || ^3.2 || ^4.0",
"symfony/event-dispatcher": "^2.8 || ^3.2 || ^4.0",
"symfony/expression-language": "^2.8 || ^3.2 || ^4.0",
"symfony/form": "^2.8 || ^3.2 || ^4.0",
"symfony/framework-bundle": "^2.8 || ^3.2 || ^4.0",
"symfony/http-foundation": "^2.8 || ^3.2 || ^4.0",
"symfony/http-kernel": "^2.8 || ^3.2 || ^4.0",
"symfony/options-resolver": "^2.8 || ^3.2 || ^4.0",
"symfony/property-access": "^2.8 || ^3.2 || ^4.0",
"symfony/routing": "^2.8 || ^3.2 || ^4.0",
"symfony/security-acl": "^2.8 || ^3.0",
"symfony/security-bundle": "^2.8 || ^3.2 || ^4.0",
"symfony/security-core": "^2.8 || ^3.2 || ^4.0",
"symfony/security-csrf": "^2.8 || ^3.2 || ^4.0",
"symfony/templating": "^2.8 || ^3.2 || ^4.0",
"symfony/translation": "^2.8 || ^3.2 || ^4.0",
"symfony/twig-bridge": "^2.8 || ^3.2 || ^4.0",
"symfony/twig-bundle": "^2.8 || ^3.2 || ^4.0",
"symfony/validator": "^2.8 || ^3.2 || ^4.0",
"twig/extensions": "^1.5",
"twig/twig": "^1.34 || ^2.0"
},"conflict": {
"jms/di-extra-bundle": "<1.9",
"sonata-project/media-bundle": "<3.7",
"sonata-project/user-bundle": "<3.3"
},
"require-dev": {
"jms/di-extra-bundle": "^1.9",
"jms/translation-bundle": "^1.4",
"matthiasnoback/symfony-dependency-injection-test": "^1.1",
"sensio/generator-bundle": "^3.1",
"sonata-project/intl-bundle": "^2.4",
"symfony/class-loader": "^2.8 || ^3.2",
"symfony/filesystem": "^2.8 || ^3.2 || ^4.0",
"symfony/phpunit-bridge": "^4.0",
"symfony/yaml": "^2.8 || ^3.2 || ^4.0"
},
"suggest": {
"jms/di-extra-bundle": "Annotations for Admin definition",
"jms/translation-bundle": "Extract message keys from Admins",
"sensio/generator-bundle": "Add sonata:admin:generate command",
"sonata-project/intl-bundle": "Add localized date and number into the list"
},
"config": {
"sort-packages": true
},
"extra": {
"branch-alias": {
"dev-master": "3.x-dev"
}
},
"autoload": {
"psr-4": {
"Sonata\AdminBundle\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"Sonata\AdminBundle\Tests\": "tests/"
}
}
}

I think this is prob a problem of versioning/compatibillity right ?

No, probably something else. Have you tried reducing this to just the affected fields? What happens if you run orm:info with this entity and just the identifier plus the two boolean fields?

composer show gives version 2.6.2 for this package (doctrine/orm) :+1:
Your mapping seems okay (a bit convoluted, though).

I'd suggest updating to the latest ORM v2.6.4 (just to ensure you have the latest bugfixes - none related to this specifically) and to isolate the ORM behaviour from the rest - you have many things being integrated (various traits and usage of SF forms).

That isolation could be done by instantiating the object, persisting it (persist + flush), and fetching it from the DB (clear + find). This process would show if the ORM is the culprit here.

Updated to 2.6.4 Thanks @lcobucci. Could you show me a little bit how to instantiating the object, persisting it (persist + flush), and fetching it from the DB (clear + find) ?

Thanks @Ocramius. The php bin/console orm:info gives me nothing but an undefined command.

Maybe doctrine:info? No idea how this is done in symfony :-P

Thanks Ocramius, got this:
image

Maybe orm:mapping:describe (doctrine:mapping:describe in symfony context?) will help further.

Closing here meanwhile: as mentioned above, you have to isolate the issue by reducing the code until the minimum reproducible scenario, without the rest of the application code.

Once it is clear if/that it is an ORM bug, then please re-open with a more reduced example, maybe to be added to https://github.com/doctrine/doctrine2/tree/master/tests/Doctrine/Tests/ORM/Functional/Ticket

I can assure you it's a doctrine-orm issue since it tells me all is up to date and when i try to use my field suddenly it says it is not mapped, i manage to get a mapping description with: php bin/console sonata:core:dump-doctrine-metadata

image

And no caches involved?

And no caches involved?

Especially metadata cache.

I cleared all caches including doctrine metadata multiples times

I got an error generating the dump of doctrine metadata here it is:

image

Thanks for the help it's now resolved after upgrading some dependencies and clearing caches it works great thanks again for the help!

Was this page helpful?
0 / 5 - 0 ratings