Symfony2:都不是属性…存在并拥有PropertyAccess的公共访问权限,但它确实存在


Symfony2 : neither property... exist and have public access with PropertyAccess, but yes it exists

在我的symfony2应用程序中,我正在克隆一个对象及其集合。我正在使用PropertyAccess类来设置属性值,但我觉得我缺少一个方法访问器,用于向集合添加元素。

编辑:我发现PropertyAccess也可以调用add方法 我的代码:
        $collectionNames = array('tags', 'objectCategories', 'groups');
        foreach ($collectionNames as $collectionName)
        {
            $collection = $accessor->getValue($this, $collectionName);
            $this->$collectionName = new ArrayCollection();
            foreach ($collection as $element)
            {
                $accessor->setValue($this, $collectionName, $element);
            }
        }

我得到以下错误:

Neither the property "objectCategories" nor one of the methods "addObjectCategory()"/"removeObjectCategory()", "setObjectCategories()", "objectCategories()", "__set()" or "__call()" exist and have public access in class "AppBundle'Entity'FoodAnalytics'Recipe".
500 Internal Server Error - NoSuchPropertyException

但是addObjectCategory方法是存在的并且具有公共访问权限你可以在我的类

中看到

如何解决这个问题?非常感谢!

编辑:整个recipe类:

<?php
//D:'Divers'Programmation'Web'foodmeup'srcRecipe.php
namespace AppBundle'Entity'FoodAnalytics;
use AppBundle'Entity'Core'Media;
use AppBundle'Entity'Core'ObjectCategory;
use AppBundle'Entity'User'User;
use AppBundle'Model'Interfaces'MediaInterface;
use AppBundle'Model'Interfaces'VoteInterface;
use AppBundle'Model'Traits'BlameableTrait;
use AppBundle'Model'Interfaces'ViewCountInterface;
use AppBundle'Model'Traits'MediaTrait;
use AppBundle'Model'Traits'ViewCountTrait;
use AppBundle'Model'Traits'VoteTrait;
use Doctrine'Common'Collections'ArrayCollection;
use Doctrine'ORM'Mapping AS ORM;
use Gedmo'Mapping'Annotation as Gedmo;
use Gedmo'Timestampable'Traits'TimestampableEntity;
use AppBundle'Model'Classes'BaseCategoryClass as BaseCategory;
use Symfony'Component'PropertyAccess'PropertyAccess;
use Symfony'Component'Validator'Constraints as Assert;
use AppBundle'Validator'Constraints as FMUAssert;
use Symfony'Component'Validator'Context'ExecutionContextInterface;
/**
 * @ORM'Entity(repositoryClass="AppBundle'Repository'FoodAnalytics'RecipeRepository")
 * @Gedmo'Tree(type="nested")
 * @ORM'HasLifecycleCallbacks
 */
class Recipe extends BaseCategory implements ViewCountInterface, VoteInterface, MediaInterface
{
    use TimestampableEntity, ViewCountTrait, BlameableTrait, VoteTrait, MediaTrait;
    /**
     * @Assert'Type(type="bool", groups={"recipe"})
     * @Assert'NotNull(groups={"recipe"})
     * @ORM'Column(type="boolean", nullable=false)
     */
    protected $isProduct = false;
    /**
     * @Assert'Type(type="integer", groups={"recipe"})
     * @ORM'Column(type="integer", nullable=true)
     */
    protected $portions;
    /**
     * @Assert'Length(min="1", max="100", groups={"recipe"})
     * @Assert'NotBlank(groups={"recipe"})
     * @ORM'Column(type="string", length=100, nullable=false)
     */
    protected $nickname;
    /**
     * @Assert'Length(max="500", groups={"recipe"})
     * @ORM'Column(type="string", length=500, nullable=true)
     */
    protected $shortDescription;
    /**
     * @Assert'Type(type="numeric", groups={"recipe"})
     * @ORM'Column(type="decimal", precision=10, scale=2, nullable=true)
     */
    protected $weight;
    /**
     * @Assert'Type(type="bool", groups={"recipe"})
     * @ORM'Column(type="boolean", nullable=false)
     */
    protected $isPrivate = false;
    /**
     * @Assert'Valid()
     * @ORM'OrderBy({"sortablePosition" = "ASC"})
     * @ORM'OneToMany(targetEntity="RecipeIngredient", mappedBy="recipe", cascade={"persist", "remove"})
     */
    protected $recipeIngredients;
    /**
     * @Assert'Valid()
     * @ORM'OrderBy({"sortablePosition" = "ASC"})
     * @ORM'OneToMany(targetEntity="RecipeAsset", mappedBy="recipe", cascade={"persist", "remove"})
     */
    protected $recipeAssets;
    /**
     * @Assert'Valid()
     * @ORM'OrderBy({"sortablePosition" = "ASC"})
     * @ORM'OneToMany(targetEntity="RecipeSubrecipe", mappedBy="parentRecipe", cascade={"persist"})
     */
    protected $subrecipes;
    /**
     * @ORM'OneToMany(targetEntity="RecipeSubrecipe", mappedBy="subrecipe")
     */
    protected $parentRecipes;
    /**
     * @Assert'Valid()
     * @ORM'OrderBy({"sortablePosition" = "ASC"})
     * @ORM'OneToMany(targetEntity="RecipeStep", mappedBy="recipe", cascade={"persist", "remove"})
     */
    protected $recipeSteps;
    /**
     * @ORM'OrderBy({"sortablePosition" = "ASC"})
     * @Assert'Valid()
     * @ORM'OneToMany(targetEntity="'AppBundle'Entity'Core'Media", mappedBy="recipe", cascade={"persist", "remove"})
     */
    protected $medias;
    /**
     * @ORM'ManyToMany(targetEntity="'AppBundle'Entity'Core'Tag", inversedBy="recipes", cascade={"persist"})
     * @ORM'JoinTable(
     *     name="recipe_tag",
     *     joinColumns={@ORM'JoinColumn(name="recipeId", referencedColumnName="id", nullable=false, onDelete="CASCADE")},
     *     inverseJoinColumns={@ORM'JoinColumn(name="tagId", referencedColumnName="id", nullable=false, onDelete="CASCADE")}
     * )
     */
    protected $tags;
    /**
     * @ORM'OneToMany(targetEntity="UserRecipe", mappedBy="recipe", cascade={"persist", "remove"})
     */
    protected $userRecipes;
    /**
     * @ORM'ManyToMany(targetEntity="AppBundle'Entity'Core'ObjectCategory", mappedBy="recipes", cascade={"persist"})
     */
    protected $objectCategories;
    /**
     * @Gedmo'TreeParent
     * @ORM'ManyToOne(targetEntity="Recipe", inversedBy="children")
     * @ORM'JoinColumn(name="parentId", referencedColumnName="id", onDelete="SET NULL")
     */
    protected $parent;
    /**
     * @ORM'OneToMany(targetEntity="Recipe", mappedBy="parent")
     */
    protected $children;
    /**
     * @ORM'ManyToMany(targetEntity="'AppBundle'Entity'User'Group", inversedBy="recipes")
     * @ORM'JoinTable(
     *     name="recipe_group",
     *     joinColumns={@ORM'JoinColumn(name="recipeId", referencedColumnName="id", onDelete="CASCADE")},
     *     inverseJoinColumns={@ORM'JoinColumn(name="groupId", referencedColumnName="id", onDelete="CASCADE")}
     * )
     */
    protected $groups;
    /**
     * @ORM'ManyToOne(targetEntity="'AppBundle'Entity'User'User")
     * @ORM'JoinColumn(name="userId", referencedColumnName="id", nullable=true)
     */
    protected $user;
    /**
     * @ORM'OneToMany(targetEntity="'AppBundle'Entity'Core'Vote", mappedBy="recipe", cascade={"persist"})
     */
    protected $votes;
    public function isShared()
    {
        return $this->userRecipes->count() > 1;
    }
    public function __toString()
    {
        return $this->name;
    }
    /**
     * http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/cookbook/implementing-wakeup-or-clone.html
     */
    public function __clone()
    {
        if ($this->id) {
            //Necessary to update slug correctly
            $this->id = null;
            $this->setSlug(null);
            $collectionNames = array('subrecipes', 'recipeIngredients', 'recipeAssets', 'recipeSteps');
            $accessor = PropertyAccess::createPropertyAccessor();
            foreach ($collectionNames as $collectionName)
            {
                $collection = $accessor->getValue($this, $collectionName);
                $this->$collectionName = new ArrayCollection();
                foreach ($collection as $element)
                {
                    $newElement = clone $element;
                    $newElement->setId(null);
                    if (property_exists(get_class($newElement), 'slug')) $newElement->setSlug(null);
                    $method = 'add' . substr(ucfirst($collectionName), 0, -1);
                    $this->$method($newElement);
                }
            }
            //The new recipe is necessarily not yet included in any other recipe
            $this->parentRecipes = new ArrayCollection();
        }
        // otherwise do nothing, do NOT throw an exception!
    }
    //Useful when cloning the recipe and keeping only the user old userrecipe (removing other users' userrecipes)
    public function setUserRecipes($userRecipes)
    {
        $this->userRecipes = $userRecipes;
    }
    /**
     * @Assert'Callback()
     * @param ExecutionContextInterface $context
     */
    public function validate(ExecutionContextInterface $context)
    {
        if (!(count($this->recipeIngredients) + count($this->subrecipes))) {
            $context
                ->buildViolation('Vous devez indiquer au moins un ingrédient ou une sous-recette')
                ->addViolation();
        }
    }
    /**
     * Sets the weight on a recipe by checking for its ingredients and subrecipes weight
     * It's a recursion with subrecipes so subrecipes shall not contain any of the parent recipes !
     *
     * @return $this
     * @ORM'PrePersist()
     */
    public function setWeight()
    {
        /**
         * @var float
         */
        $weight=0;
        /** @var $recipeIngredient RecipeIngredient */
        foreach($this->getRecipeIngredients() as $recipeIngredient)
        {
            if ($recipeIngredient->getUnit()->getName() == 'g')
            {
                $weight += $recipeIngredient->getQuantity();
            }
            elseif ($recipeIngredient->getUnit()->getName() == 'U')
            {
                $weight += $recipeIngredient->getQuantity() * $recipeIngredient->getProduct()->getUnitWeight();
            }
            elseif ($recipeIngredient->getUnit()->getName() == 'produit')
            {
                $weight += $recipeIngredient->getQuantity() * $recipeIngredient->getProduct()->getProductWeight();
            }
        }
        foreach($this->getSubrecipes() as $subrecipe)
        {
            /**
             * @var $subrecipe RecipeSubrecipe
             */
            $weight += $subrecipe->getSubrecipe()->getWeight();
        }
        $this->weight = $weight;
        return $this;
    }
    /**
     * Get weight
     *
     * @return float
     */
    public function getWeight()
    {
        return $this->weight;
    }
    /**
     * Constructor
     * @param User $user
     */
    public function __construct(User $user)
    {
        parent::__construct();
        $this->recipeIngredients = new ArrayCollection();
        $this->recipeAssets = new ArrayCollection();
        $this->subrecipes = new ArrayCollection();
        $this->groups = new ArrayCollection();
        $this->userRecipes = new ArrayCollection();
        $this->recipeSteps = new ArrayCollection();
        $this->medias = new ArrayCollection();
        $this->objectCategories = new ArrayCollection();
        $this->tags = new ArrayCollection();
        $this->parentRecipes = new ArrayCollection();
        $this->children = new ArrayCollection();
        $this->votes = new ArrayCollection();
        $this->user = $user;
    }
    /**
     * Get isPrivate
     *
     * @return integer
     */
    public function getIsPrivate()
    {
        return $this->isPrivate;
    }
    /**
     * Set isPrivate
     *
     * @param $isPrivate
     * @return $this
     */
    public function setIsPrivate($isPrivate)
    {
        $this->isPrivate = $isPrivate;
        return $this;
    }
    /**
     * Set portions
     *
     * @param string $portions
     *
     * @return Recipe
     */
    public function setPortions($portions)
    {
        $this->portions = $portions;
        return $this;
    }
    /**
     * Get portions
     *
     * @return float
     */
    public function getPortions()
    {
        return $this->portions;
    }
    /**
     * Set nickname
     *
     * @param string $nickname
     *
     * @return Recipe
     */
    public function setNickname($nickname)
    {
        $this->nickname = $nickname;
        return $this;
    }
    /**
     * Get nickname
     *
     * @return string
     */
    public function getNickname()
    {
        return $this->nickname;
    }
    /**
     * Set shortDescription
     *
     * @param string $shortDescription
     *
     * @return Recipe
     */
    public function setShortDescription($shortDescription)
    {
        $this->shortDescription = $shortDescription;
        return $this;
    }
    /**
     * Get shortDescription
     *
     * @return string
     */
    public function getShortDescription()
    {
        return $this->shortDescription;
    }
    /**
     * Set slug
     *
     * @param string $slug
     *
     * @return Recipe
     */
    public function setSlug($slug)
    {
        $this->slug = $slug;
        return $this;
    }
    /**
     * Get slug
     *
     * @return string
     */
    public function getSlug()
    {
        return $this->slug;
    }
    /**
     * Add recipeIngredient
     *
     * @param RecipeIngredient $recipeIngredient
     *
     * @return Recipe
     */
    public function addRecipeIngredient(RecipeIngredient $recipeIngredient)
    {
        $this->recipeIngredients[] = $recipeIngredient;
        //To be added so as to set the recipeId of the recipeIngredient when a new recipe is created
        $recipeIngredient->setRecipe($this);
        return $this;
    }
    /**
     * Remove recipeIngredient
     *
     * @param RecipeIngredient $recipeIngredient
     */
    public function removeRecipeIngredient(RecipeIngredient $recipeIngredient)
    {
        $this->recipeIngredients->removeElement($recipeIngredient);
    }
    /**
     * Get recipeIngredients
     *
     * @return 'Doctrine'Common'Collections'Collection
     */
    public function getRecipeIngredients()
    {
        return $this->recipeIngredients;
    }
    /**
     * Add recipeAsset
     *
     * @param RecipeAsset $recipeAsset
     *
     * @return Recipe
     */
    public function addRecipeAsset(RecipeAsset $recipeAsset)
    {
        if (!$this->recipeAssets->contains($recipeAsset))
        {
            $this->recipeAssets[] = $recipeAsset;
            $recipeAsset->setRecipe($this);
        }
        return $this;
    }
    /**
     * Remove recipeAsset
     *
     * @param RecipeAsset $recipeAsset
     */
    public function removeRecipeAsset(RecipeAsset $recipeAsset)
    {
        $this->recipeAssets->removeElement($recipeAsset);
    }
    /**
     * Get recipeAssets
     *
     * @return 'Doctrine'Common'Collections'Collection
     */
    public function getRecipeAssets()
    {
        return $this->recipeAssets;
    }
    /**
     * Add subrecipe
     *
     * @param RecipeSubrecipe $subrecipe
     *
     * @return Recipe
     */
    public function addSubrecipe(RecipeSubrecipe $subrecipe)
    {
        $this->subrecipes[] = $subrecipe;
        $subrecipe->setParentRecipe($this);
        return $this;
    }
    /**
     * Remove subrecipe
     *
     * @param RecipeSubrecipe $subrecipe
     */
    public function removeSubrecipe(RecipeSubrecipe $subrecipe)
    {
        $this->subrecipes->removeElement($subrecipe);
    }
    /**
     * Get subrecipes
     *
     * @return 'Doctrine'Common'Collections'Collection
     */
    public function getSubrecipes()
    {
        return $this->subrecipes;
    }
    /**
     * Add parentRecipe
     *
     * @param RecipeSubrecipe $parentRecipe
     *
     * @return Recipe
     */
    public function addParentRecipe(RecipeSubrecipe $parentRecipe)
    {
        $this->parentRecipes[] = $parentRecipe;
        $parentRecipe->setParentRecipe($this);
        return $this;
    }
    /**
     * Remove parentRecipe
     *
     * @param RecipeSubrecipe $parentRecipe
     */
    public function removeParentRecipe(RecipeSubrecipe $parentRecipe)
    {
        $this->parentRecipes->removeElement($parentRecipe);
    }
    /**
     * Get parentRecipes
     *
     * @return 'Doctrine'Common'Collections'Collection
     */
    public function getParentRecipes()
    {
        return $this->parentRecipes;
    }
    /**
     * Add recipeStep
     *
     * @param RecipeStep $recipeStep
     *
     * @return Recipe
     */
    public function addRecipeStep(RecipeStep $recipeStep)
    {
        $this->recipeSteps[] = $recipeStep;
        $recipeStep->setRecipe($this);
        return $this;
    }
    /**
     * Remove recipeStep
     *
     * @param RecipeStep $recipeStep
     */
    public function removeRecipeStep(RecipeStep $recipeStep)
    {
        $this->recipeSteps->removeElement($recipeStep);
    }
    /**
     * Get recipeSteps
     *
     * @return 'Doctrine'Common'Collections'Collection
     */
    public function getRecipeSteps()
    {
        return $this->recipeSteps;
    }
    /**
     * Add media
     *
     * @param 'AppBundle'Entity'Core'Media $media
     *
     * @return Recipe
     */
    public function addMedia('AppBundle'Entity'Core'Media $media)
    {
        $media->setRecipe($this);
        $this->medias[] = $media;
        return $this;
    }
    /**
     * Remove media
     *
     * @param 'AppBundle'Entity'Core'Media $media
     */
    public function removeMedia('AppBundle'Entity'Core'Media $media)
    {
        $this->medias->removeElement($media);
    }
    /**
     * Get medias
     *
     * @return 'Doctrine'Common'Collections'Collection
     */
    public function getMedias()
    {
        return $this->medias;
    }
    /**
     * Sets user.
     *
     * @param  string $user
     * @return $this
     */
    public function setUser($user)
    {
        $this->user = $user;
        return $this;
    }
    /**
     * Returns user.
     *
     * @return User
     */
    public function getUser()
    {
        return $this->user;
    }
    /**
     * Add objectCategory
     *
     * @param ObjectCategory $objectCategory
     *
     * @return Recipe
     */
    public function addObjectCategory(ObjectCategory $objectCategory)
    {
        $objectCategory->addRecipe($this);
        $this->objectCategories[] = $objectCategory;
        return $this;
    }
    /**
     * Remove objectCategory
     *
     * @param ObjectCategory $objectCategory
     */
    public function removeObjectCategory(ObjectCategory $objectCategory)
    {
        $this->objectCategories->removeElement($objectCategory);
    }
    /**
     * Get objectCategories
     *
     * @return 'Doctrine'Common'Collections'Collection
     */
    public function getObjectCategories()
    {
        return $this->objectCategories;
    }
    /**
     * @return array
     */
    public function getObjectCategoriesWithParents()
    {
        $categories = array();
        /** @var $category ObjectCategory */
        foreach ($this->objectCategories as $category)
        {
            if ($category->getParent()) $categories[] = $category->getParent();
            $categories[] = $category;
        }
        return array_unique($categories);
    }

    /**
     * Set isProduct
     *
     * @param boolean $isProduct
     *
     * @return Recipe
     */
    public function setIsProduct($isProduct)
    {
        $this->isProduct = $isProduct;
        return $this;
    }
    /**
     * Get isProduct
     *
     * @return boolean
     */
    public function getIsProduct()
    {
        return $this->isProduct;
    }
    /**
     * Add userRecipe
     *
     * @param 'AppBundle'Entity'FoodAnalytics'UserRecipe $userRecipe
     *
     * @return Recipe
     */
    public function addUserRecipe('AppBundle'Entity'FoodAnalytics'UserRecipe $userRecipe)
    {
        $this->userRecipes[] = $userRecipe;
        return $this;
    }
    /**
     * Remove userRecipe
     *
     * @param 'AppBundle'Entity'FoodAnalytics'UserRecipe $userRecipe
     */
    public function removeUserRecipe('AppBundle'Entity'FoodAnalytics'UserRecipe $userRecipe)
    {
        $this->userRecipes->removeElement($userRecipe);
    }
    /**
     * Get userRecipes
     *
     * @return 'Doctrine'Common'Collections'Collection
     */
    public function getUserRecipes()
    {
        return $this->userRecipes;
    }
    /**
     * Get duration
     *
     * @return 'Datetime
     */
    public function getOwnDuration()
    {
        $duration = 0;
        /** @var $recipeStep RecipeStep */
        foreach ($this->recipeSteps as $recipeStep)
        {
            $duration += $recipeStep->getDuration();
        }
        return $duration;
    }
    /**
     * Get duration
     *
     * @return int
     */
    public function getRawTotalDuration()
    {
        $duration = 0;
        /** @var $subrecipe RecipeSubrecipe */
        foreach ($this->subrecipes as $subrecipe)
        {
            $duration += $subrecipe->getSubrecipe()->getRawTotalDuration();
        }
        $duration += $this->getOwnDuration();
        return $duration;
    }
    /**
     * Get duration
     *
     * @param int $factor
     * @return string
     */
    public function getTotalDuration($factor = 1)
    {
        $seconds = $this->getRawTotalDuration() * $factor;
        $hours = floor($seconds/3600);
        $seconds -= $hours * 3600;
        $minutes = floor($seconds/60);
        $seconds -= $minutes *60;
        $string='';
        if ($hours) $string .= $hours . 'h';
        $string = $string ? $string . ' ' : $string;
        if ($minutes) $string.= $minutes .'min';
        $string = $string ? $string . ' ' : $string;
        if ($seconds) $string .= $seconds . 's';
        return trim($string);
    }
    /**
     * Add tags
     *
     * @param 'AppBundle'Entity'Core'Tag $tags
     * @return Recipe
     */
    public function addTag('AppBundle'Entity'Core'Tag $tags)
    {
        $this->tags[] = $tags;
        return $this;
    }
    /**
     * Remove tags
     *
     * @param 'AppBundle'Entity'Core'Tag $tags
     */
    public function removeTag('AppBundle'Entity'Core'Tag $tags)
    {
        $this->tags->removeElement($tags);
    }
    /**
     * Get tags
     *
     * @return 'Doctrine'Common'Collections'Collection 
     */
    public function getTags()
    {
        return $this->tags;
    }
    /**
     * Add group
     *
     * @param 'AppBundle'Entity'User'Group $group
     *
     * @return Recipe
     */
    public function addGroup('AppBundle'Entity'User'Group $group)
    {
        if (!$this->groups->contains($group))
        {
            $group->addRecipe($this);
            $this->groups[] = $group;
        }
        return $this;
    }
    /**
     * Remove group
     *
     * @param 'AppBundle'Entity'User'Group $group
     */
    public function removeGroup('AppBundle'Entity'User'Group $group)
    {
        $this->groups->removeElement($group);
    }
    /**
     * Get groups
     *
     * @return 'Doctrine'Common'Collections'Collection
     */
    public function getGroups()
    {
        return $this->groups;
    }

    /**
     * @return $this
     */
    public function reinitiateGroups()
    {
        $this->groups = new ArrayCollection();
        return $this;
    }
}

你可以这样做:

$var = $acc->getValue($this,$index);
$var->addElement('element');
$acc->setValue($this,$index,$var);

it'll work fine

[编辑]

我的代码将工作与您的实际代码,因为你正在使用的ArrayCollection在你的类。

当你得到 的值时

getValue($this,$index)

,它返回给你一个ArrayCollection对象,它已经有了一个adelement方法,所以这应该没问题

好的,错误是在我使用访问器的方式。下面的编辑可以解决这个问题:

        foreach ($collectionNames as $collectionName => $clone)
        {
            $collection = $accessor->getValue($this, $collectionName);
            $this->$collectionName = new ArrayCollection();
            $newCollection = new ArrayCollection();
            foreach ($collection as $element)
            {
                $newElement = $clone ? clone $element : $element;
                $newCollection->add($newElement);
            }
            $accessor->setValue($this, $collectionName, $newCollection);
        }