konrad_firm
konrad_firm

Reputation: 867

Symfony3: Database and Entity settings: Neither property … nor method …nor method … exists in class

I know there are similar questions, but none of the solutions work for Symfony 3.x.

So I have three entities, User, Role and Permission. User has Roles (ManyToMany) and Permissions (also ManyToMany). And then I have a form, and while Permissions work fine, Roles do not.

The only difference I can see, is that a function returning roles isn't called getRoles as it should(?), because a function with this name has to return array of strings (not array of role entities) to meet expectations of the AdvancedUserInterface, that is why another function (getRoleEntities) returns $this->roles, but I believe I reflected it while building a form.

Here is a shortened version of the User entity class:

/**
 * @ORM\Table(name="user")
 * @ORM\Entity(repositoryClass="AppBundle\Repository\UserRepository")
 */
class User implements AdvancedUserInterface, \Serializable {
    //id, username, personalname, password, email and isactive ommited

    /**
     *
     * @ORM\ManyToMany(targetEntity="AppBundle\Entity\Permission", cascade = {"persist"})
     * @ORM\JoinTable(name="user_permission")
     */
    private $permissions;//this works

    /**
     *
     * @ORM\ManyToMany(targetEntity="AppBundle\Entity\Role", cascade = {"persist"})
     * @ORM\JoinTable(name="user_role")
     */
    private $roles;//this doesn't work


    public function __construct() {
        $this->permission = new ArrayCollection();
        $this->roles = new ArrayCollection();
    }

    //irrelevant getters/setters ommited

    /**
     * Add Permission
     *
     * @param \AppBundle\Entity\Permission $userPermission
     *
     * @return User
     */
    public function addPermission(\AppBundle\Entity\Permission $userPermission) {
        $this->permissions[] = $userPermission;
        return $this;
    }

    /**
     * Remove Permission
     *
     * @param \AppBundle\Entity\Permission $userPermission
     */
    public function removePermission(\AppBundle\Entity\Permission $userPermission) {
        $this->permissions->removeElement($userPermission);
    }

    /**
     * Get Permissions
     *
     * @return \Doctrine\Common\Collections\Collection
     */
    public function getPermissions() {
        return $this->permissions;
    }

    ////////////////////////////////
    //roles

    /**
     * Add role
     * @param \AppBundle\Entity\Role $role
     *
     * @return User
     */
    public function addRoleEntity(\AppBundle\Entity\Role $role) {
        $this->roles[] = $role;
        return $this;
    }

    /**
     * Remove role
     * @param \AppBundle\Entity\Role $role
     */
    public function removeRoleEntity(\AppBundle\Entity\Role $role) {
        $this->roleRoles->removeElement($role);
    }

    /**
     * I know this one should simply return $this->roles, but it has to return array of strings to meet expectations of the AdvancedUserInterface, that is why another function (getRoleEntities) returns $this->roles
     * @return array
     */
    public function getRoles() {
        $ret_val = array();
        $roles = $this->getRoleEntities();

        if ($roles) {
            foreach ($roles as $role) {
                $ret_val[] = $role->getRoleName();
            }
        }
        return $ret_val;
    }

    /**
     * Get roles
     */
    public function getRoleEntities() {
        return $this->roles;
    }

}

And here is how I build a form:

    $em = $this->getDoctrine()->getManager();
    $user = $em->find('AppBundle:User',1);//just for testing


    $form = $this->createFormBuilder($user)
        ->add('personal_name', \Symfony\Component\Form\Extension\Core\Type\TextType::class, array('label' => 'Imię i nazwisko: '))
        ->add('is_active', \Symfony\Component\Form\Extension\Core\Type\CheckboxType::class, array('label' => 'Active: ','required' => false))
        ->add('permissions',  \Symfony\Bridge\Doctrine\Form\Type\EntityType::class , array(
            'class' => 'AppBundle\Entity\Permission', 
            'multiple' => true,
            'expanded' => true
        ))
        ->add('roleEntities',  \Symfony\Bridge\Doctrine\Form\Type\EntityType::class , array(
            'class' => 'AppBundle\Entity\Role', 
        ))

        ->add('save', \Symfony\Component\Form\Extension\Core\Type\SubmitType::class, array('label' => 'Save'))
        ->getForm();    

And when I'm opening a page I get this exception:

Neither the property "roleEntities" nor one of the methods "addRoleEntity()"/"removeRoleEntity()", "setRoleEntities()", "roleEntities()", "__set()" or "__call()" exist and have public access in class "AppBundle\Entity\User".

ps. I tagged this "symfony2", because AFAIK there are no big differences between 2.9 and 3.0

Upvotes: 1

Views: 655

Answers (1)

konrad_firm
konrad_firm

Reputation: 867

OK, fortunately guys from #Symfony irc, helped me, there are a few issues there:

  1. functions like addRoleEntity should rather be called after the variable, e.g. addRole

  2. Like @malcom mentioned, while building the form, instead of:

    ->add('roleEntities', \Symfony\Bridge\Doctrine\Form\Type\EntityType::class , array( 'class' => 'AppBundle\Entity\Role',

It should be:

->add('roles', \Symfony\Bridge\Doctrine\Form\Type\EntityType::class , array(
            'class' => 'AppBundle\Entity\Role', 
            'multiple' => true,

)

Because this is how the variable is named. Plus, since this is ManyToMany I also added 'multiple' => true, otherwise it did save, but incorectly loaded this information.

3.It went further, and a new error appeared: Can not read the choices from the choice list.

I changed the body of the getRoles method to:

return $this->roles->toArray(); 

And it worked.

The last idea is mine, not from the IRC, I'm saying this, because I don't like this solution. If it is a bad solution, then it's my fault.

Upvotes: 0

Related Questions