简体   繁体   中英

Access User Scores on Many-to-One Relationship using Symfony 3

I'm creating an app that keeps user scores in the database based on questions they solve. I have User, Problem and Submission entities. For all of them I have One-to-Many relationship from the User entity. The problem entity has the point field that holds the score of a problem. I'm trying to retrieve all users with their total points.

Here is my controller;

 $userService = $this->container->get('userservice');
 $users = $userService->findAll();
  foreach ($users as $user){
        $usersWPoints = $user->getSubmissions()->getProblemId()->getPoints;
    }

However this returns the following error;

Attempted to call an undefined method named "getProblemId" of class "Doctrine\ORM\PersistentCollection".

Here are my models

User.php

/**
* Class User
* @package AppBundle\Entity
* @ORM\Entity(repositoryClass="AppBundle\Repository\UserRepository")
* @ORM\Table(name="user")
* @ORM\HasLifecycleCallbacks()
* @UniqueEntity(fields="username", message="Email already taken")
*
*/
class User implements UserInterface
{

/**
 * @ORM\Id
 * @ORM\Column(type="integer")
 * @ORM\GeneratedValue(strategy="AUTO")
 */
private $id;


/**
 * @ORM\Column(type="string", length=255, unique=true)
 * @Assert\NotBlank(message="Please enter a valid email address")
 * @Assert\Email()
 */
private $username;

/**
 * @ORM\Column(type="string", length=255, unique=true)
 * @Assert\NotBlank(message="Please enter a valid email address")
 */
private $usrname;

/**
 * @Assert\NotBlank()
 * @Assert\Length(max=4096)
 */
private $plainPassword;

/**
 * The below length depends on the "algorithm" you use for encoding
 * the password, but this works well with bcrypt.
 *
 * @ORM\Column(type="string", length=64)
 */
private $password;

/**
 * @ORM\Column(type="string", length=255, unique=true)
 * @Assert\NotBlank(message="Please enter a valid name")
 */
private $fullname;

/**
 * @var array
 * @ORM\Column(name="roles", type="json_array")
 */
protected $roles;

/**
 * @ORM\OneToMany(targetEntity="AppBundle\Entity\Problem", mappedBy="createdby")
 */
protected $problems;

/**
 * @ORM\OneToMany(targetEntity="AppBundle\Entity\Feed", mappedBy="createdby")
 */
protected $feeds;


/**
 * @ORM\OneToMany(targetEntity="AppBundle\Entity\Comment", mappedBy="createdby")
 */
protected $comments;

/**
 * @ORM\OneToMany(targetEntity="AppBundle\Entity\Submission", mappedBy="user_id")
 */
protected $submissions;


// other properties and methods

public function getUsername()
{
    return $this->username;
}

public function setUsername($username)
{
    $this->username = $username;
}

public function getPlainPassword()
{
    return $this->plainPassword;
}

public function setPlainPassword($password)
{
    $this->plainPassword = $password;
}

public function getPassword()
{
    return $this->password;
}

public function setPassword($password)
{
    $this->password = $password;
}

public function getSalt()
{
    // The bcrypt algorithm doesn't require a separate salt.
    // You *may* need a real salt if you choose a different encoder.
    return null;
}

// other methods, including security methods like getRoles()

/**
 * @return array
 */
public function getRoles()
{
    return $this->roles;
}

public function setRoles(array $roles){
    $this->roles = $roles;
    return $this;
}

/**
 * @return mixed
 */
public function getFullname()
{
    return $this->fullname;
}

/**
 * @param mixed $fullname
 */
public function setFullname($fullname)
{
    $this->fullname = $fullname;
}

/**
 * @return mixed
 */
public function getUsrname()
{
    return $this->usrname;
}

/**
 * @param mixed $usrname
 */
public function setUsrname($usrname)
{
    $this->usrname = $usrname;
}


/**
 * Removes sensitive data from the user.
 *
 * This is important if, at any given point, sensitive information like
 * the plain-text password is stored on this object.
 */
public function eraseCredentials()
{
}

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

/**
 * @return \Doctrine\Common\Collections\Collection
 */
public function getSubmissions()
{
    return $this->submissions;
}

Problem.php

/**
 * Class Problem
 * @package AppBundle\Entity
 * @ORM\Entity(repositoryClass="AppBundle\Repository\ProblemRepository")
 * @ORM\Table(name="problem")
 * @ORM\HasLifecycleCallbacks()
 *
 */
class Problem
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=255, unique=True)
     * @Assert\NotBlank(message="Please enter a valid title")
     */
    protected $title;

    /**
     * @ORM\Column(type="string")
     * @Assert\NotBlank(message="Please enter a valid description")
     */
    protected $description;

    /**
     * @ORM\Column(type="string")
     * @Assert\NotBlank(message="Please enter a valid value")
     */
    protected $points;

    /**
     * @ORM\Column(type="string")
     * @Assert\NotBlank(message="Please enter a valid flag")
     */
    protected $flag;

    /**
     * @ORM\Column(type="string")
     * @Assert\NotBlank(message="Please enter a valid value")
     */
    protected $category;

    /**
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\User", inversedBy="problems")
     * @ORM\JoinColumn(name="createdby", referencedColumnName="id")
     */
    protected $createdby;

    /**
     * @ORM\OneToMany(targetEntity="AppBundle\Entity\Submission", mappedBy="problem_id")
     */
    protected $submissions;

    /**
     * @Gedmo\Slug(fields={"title"})
     * @ORM\Column(type="string", length=255, unique=false,)
     */
    protected $slug;


    /**
     * @return mixed
     */
    public function getTitle()
    {
        return $this->title;
    }

    /**
     * @param mixed $title
     */
    public function setTitle($title)
    {
        $this->title = $title;
    }

    /**
     * @return mixed
     */
    public function getDescription()
    {
        return $this->description;
    }

    /**
     * @param mixed $description
     */
    public function setDescription($description)
    {
        $this->description = $description;
    }

    /**
     * @return mixed
     */
    public function getPoints()
    {
        return $this->points;
    }

    /**
     * @param mixed $points
     */
    public function setPoints($points)
    {
        $this->points = $points;
    }

    /**
     * @return mixed
     */
    public function getFlag()
    {
        return $this->flag;
    }

    /**
     * @param mixed $flag
     */
    public function setFlag($flag)
    {
        $this->flag = $flag;
    }

    /**
     * @return mixed
     */
    public function getCategory()
    {
        return $this->category;
    }

    /**
     * @param mixed $category
     */
    public function setCategory($category)
    {
        $this->category = $category;
    }

    /**
     * @return mixed
     */
    public function getCreatedby()
    {
        return $this->createdby;
    }

    /**
     * @param mixed $createdby
     */
    public function setCreatedby($createdby)
    {
        $this->createdby = $createdby;
    }






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

    /**
     * Set slug
     *
     * @param string $slug
     *
     * @return Problem
     */
    public function setSlug($slug)
    {
        $this->slug = $slug;

        return $this;
    }

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

    /**
     * @return mixed
     */
    public function getSubmissions()
    {
        return $this->submissions;
    }

    /**
     * @param mixed $submissions
     */
    public function setSubmissions($submissions)
    {
        $this->submissions = $submissions;
    }    
}

Submission.php

class Submission
{

    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Problem", inversedBy="submissions")
     * @ORM\JoinColumn(name="problem_id", referencedColumnName="id")
     */
    protected $problem_id;

    /**
     * @ORM\Column(type="boolean")
     */
    protected $correct = false;

    /**
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\User", inversedBy="submissions")
     * @ORM\JoinColumn(name="user_id", referencedColumnName="id")
     */
    protected $user_id;

    /**
     * @ORM\Column(type="string")
     * @Assert\NotBlank(message="Flag cannot be blank")
     */
    protected $submission_flag;

    /**
     * @return mixed
     */
    public function getProblemId()
    {
        return $this->problem_id;
    }

    /**
     * @param mixed $problem_id
     */
    public function setProblemId($problem_id)
    {
        $this->problem_id = $problem_id;
    }

    /**
     * @return mixed
     */
    public function getCorrect()
    {
        return $this->correct;
    }

    /**
     * @param mixed $correct
     */
    public function setCorrect($correct)
    {
        $this->correct = $correct;
    }

    /**
     * @return mixed
     */
    public function getUserId()
    {
        return $this->user_id;
    }

    /**
     * @param mixed $user_id
     */
    public function setUserId($user_id)
    {
        $this->user_id = $user_id;
    }

    /**
     * @return mixed
     */
    public function getSubmissionFlag()
    {
        return $this->submission_flag;
    }

    /**
     * @param mixed $submission_flag
     */
    public function setSubmissionFlag($submission_flag)
    {
    $this->submission_flag = $submission_flag;
}

}

Any suggestions on accessing each user and their total points would be highly appreciated.

getSubmissions() returns collenction and getProblemId() is method of Submissions. So as soon as you have many Submissions fo each user - i would create some getTotalPoints() method for User where you can run in foreach. This kind of way:

public function getTotalPoints()
{
    $submissions = $this->getSubmissions();
    $points = 0;

    foreach ($submissions as $submission) {
        $points += $submission->getProblemId()->getPoints();
    }

    return $points;
}

You could do something like this:

$userService = $this->container->get('userservice');
$users = $userService->findAll();

$pointPerUser = array();
foreach ($users as $user){
        $userSubmissions = $user->getSubmissions();
        $pointPerUser[$user->getId()] = 0;
        foreach ($userSubmissions as $userSubmission) {
            // Probably here you want to check if the submission is correct
            $pointPerUser[$user->getId()] += $userSubmission->getProblemId()->getPoints();
        } 
}

By the way, the submission attribute shouldn't be $problem_id but $problem, and the method is getProblem(), as you are getting a Problem instance, not an id. The field name for the table is ok, as you are storing an id.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM