") * @Serializer\Expose() */ public $votes; /** * @ORM\OneToMany(targetEntity="App\Entity\StackOfVotes", mappedBy="poll", orphanRemoval=true, cascade={"persist", "remove"}) * @Serializer\Expose() */ public $stacksOfVotes; /** * @ORM\OneToMany(targetEntity="App\Entity\Choice", mappedBy="poll", orphanRemoval=true, cascade={"persist", "remove"}) * @Serializer\Expose() * @Serializer\Type("ArrayCollection") */ public $choices; /** * @ORM\OneToMany(targetEntity="App\Entity\Comment", mappedBy="poll", orphanRemoval=true, cascade={"persist", "remove"}) * @Serializer\Expose() * @Serializer\Type("ArrayCollection") */ public $comments; /** * number of days from now for default expiracy date * @var int * @Serializer\Expose() */ public $defaultExpiracyDaysFromNow = 60; /** * vote restricted by a password in md5 format * @ORM\Column(type="string", length=255, nullable=true) */ private $password; /** * used to allow administration * @ORM\Column(type="string", length=255) * @Serializer\Type("string") */ private $adminKey; private $maxChoicesLimit = 25; public function __construct() { $this->initiate(); $this->setCreatedAt( new DateTime() ); $this->setAdminKey( $this->generateRandomKey() ); $this->votes = new ArrayCollection(); $this->stacksOfVotes = new ArrayCollection(); $this->choices = new ArrayCollection(); $this->comments = new ArrayCollection(); } private function initiate() { $this->votes = new ArrayCollection(); $this->stacksOfVotes = new ArrayCollection(); $this->choices = new ArrayCollection(); $this->comments = new ArrayCollection(); $this->setAdminKey( $this->generateRandomKey() ); $this->setCreatedAt( new DateTime() ); $this->setExpiracyDate( $this->addDaysToDate( new DateTime(), $this->defaultExpiracyDaysFromNow ) ); $this->setAllowedAnswers( [ 'yes', 'maybe', 'no' ] ); } public function setCreatedAt( DateTimeInterface $createdAt ): self { $this->createdAt = $createdAt; return $this; } public function displayForAdmin() { $content = $this->display(); $content[ 'owner' ] = $this->getOwner()->displayForAdmin(); $content[ 'admin_key' ] = $this->getAdminKey(); $content[ 'password_hash' ] = $this->getPassword(); $content[ 'id' ] = $this->getId(); return $content; } // counts each number of answer for this choice public function display() { $computedAnswers = $this->computeAnswers(); $displayedStackOfVotes = []; foreach ( $this->getStacksOfVotes() as $stack ) { $displayedStackOfVotes[] = $stack->display(); } $displayedChoices = []; foreach ( $this->getChoices() as $choice ) { $displayedChoices[] = $choice->display( $this->getKind() ); } $displayedComments = []; foreach ( $this->getComments() as $comment ) { $displayedComments[] = $comment->display(); } $resp = [ 'title' => $this->getTitle(), 'description' => $this->getDescription(), 'choices_grouped' => $computedAnswers[ 'grouped_dates' ], 'created_at' => $this->getCreatedAt()->format( 'c' ), 'expiracy_date' => $this->getExpiracyDate()->format( 'c' ), 'votes_max' => $this->getVotesMax(), 'custom_url' => $this->getCustomUrl(), 'choices_max' => $this->getChoicesMax(), 'kind' => $this->getKind(), 'allowed_answers' => $this->getAllowedAnswers(), 'votes_allowed' => $this->getVotesAllowed(), 'modification_policy' => $this->getModificationPolicy(), 'hide_results' => $this->getHideResults(), 'show_results_even_if_password' => $this->getShowResultEvenIfPasswords(), 'owner' => [ 'pseudo' => $this->getOwner()->getPseudo(), ] , 'choices' => $computedAnswers[ 'answers' ], 'password_protected' => $this->getPassword() ? 'yes' : 'no', 'max_score' => $computedAnswers[ 'max_score' ], 'stacks' => $displayedStackOfVotes, 'comments' => $displayedComments, ]; // if ( $this->getKind() == 'text' ) { // $resp[ 'choices' ] = $computedAnswers[ 'grouped_dates' ]; // $resp[ 'choices_grouped' ] = $computedAnswers[ 'answers' ]; // } elseif ( $this->getKind() == 'date' ) { // $resp[ 'choices' ] = $computedAnswers[ 'answers' ]; // $resp[ 'choices_grouped' ] = $computedAnswers[ 'grouped_dates' ]; // } return $resp; } public function computeAnswers() { $computedArray = []; $grouped_dates = []; $maxScore = 0; if ( $this->getKind() == 'date' ) { foreach ( $this->getChoices() as $choice ) { $boom = explode( ' >>> ', $choice->getName() ); // handle sub time slices if ( count( $boom ) == 2 ) { if ( ! isset( $grouped_dates[ $boom[ 0 ] ] ) ) { $grouped_dates[ $boom[ 0 ] ] = [ "date_string" => $boom[ 0 ], "choices" => [], ]; } $grouped_dates[ $boom[ 0 ] ][ "choices" ][] = [ "choice_id" => $choice->getId(), "name" => $boom[ 1 ], ]; } elseif(count( $boom ) == 1){ $name = $choice->getName(); $grouped_dates[ $name ] = [ "date_string" => $name, "choices" => [], ]; $grouped_dates[ $name ][ "choices" ][] = [ "choice_id" => $choice->getId(), "name" => $name, ]; } } } elseif ( $this->getKind() == 'text' ) { foreach ( $this->getChoices() as $choice ) { $name = $choice->getName(); if ( ! isset( $grouped_dates[ $name ] ) ) { $grouped_dates[ $name ] = [ "date_string" => $name, "choices" => [], ]; } $grouped_dates[ $name ][ "choices" ][] = [ "choice_id" => $choice->getId(), "name" => $name, ]; } } $scoreInfos = [ 'id' => null, 'name' => null, 'score' => 0, 'created_at' => null, 'yes' => [ 'count' => 0, 'people' => [], ], 'maybe' => [ 'count' => 0, 'people' => [], ], 'no' => [ 'count' => 0, 'people' => [], ], ]; // first, prefill all choices foreach ( $this->getChoices() as $choice ) { $computedArray[ $choice->getId() ] = array_merge( $scoreInfos, $choice->display( $this->getKind() ) ); } // then, compute stack of votes scores on each choice foreach ( $this->getStacksOfVotes() as $stack_of_vote ) { foreach ( $stack_of_vote->getVotes() as $vote ) { $answer = $vote->getValue(); $choice_id = $vote->getChoice()->getId(); $choice_url = $vote->getChoice()->getUrl(); if ( ! isset( $computedArray[ $choice_id ] ) ) { $computedArray[ $choice_id ] = [ 'id' => $choice_id, 'url' => $choice_url, 'name' => $vote->getChoice()->getName(), 'score' => 0, 'yes' => [ 'count' => 0, 'people' => [], ], 'maybe' => [ 'count' => 0, 'people' => [], ], 'no' => [ 'count' => 0, 'people' => [], ], ]; } $computedArray[ $choice_id ][ $answer ][ 'count' ] ++; $computedArray[ $choice_id ][ $answer ][ 'people' ][] = $stack_of_vote->getOwner()->getPseudo(); if ( $answer == 'yes' ) { $computedArray[ $choice_id ][ 'score' ] += 1; } elseif ( $answer == 'maybe' ) { $computedArray[ $choice_id ][ 'score' ] += 0.5; } // compare with max value if ( $computedArray[ $choice_id ][ 'score' ] > $maxScore ) { $maxScore = $computedArray[ $choice_id ][ 'score' ]; } } } $answersWithStats = []; foreach ( $computedArray as $choice_stat ) { $answersWithStats[] = $choice_stat; } $groupsOfDates = []; foreach ( $grouped_dates as $group ) { $ii = 0; foreach ( $group[ "choices" ] as $slice ) { $slice[ 'score' ] = $computedArray[ $slice[ 'choice_id' ] ][ 'score' ]; $slice[ 'yes' ] = $computedArray[ $slice[ 'choice_id' ] ][ 'yes' ]; $slice[ 'maybe' ] = $computedArray[ $slice[ 'choice_id' ] ][ 'maybe' ]; $slice[ 'no' ] = $computedArray[ $slice[ 'choice_id' ] ][ 'no' ]; $slice[ 'id' ] = $slice[ 'choice_id' ]; $group[ "choices" ][ $ii ] = $slice; $ii ++; } $groupsOfDates[] = $group; } return [ 'answers' => $answersWithStats, 'grouped_dates' => $groupsOfDates, 'max_score' => $maxScore, ]; } /** * @return Collection|Choice[] */ public function getChoices(): Collection { return $this->choices; } public function getKind(): ?string { return $this->kind; } public function setKind( string $kind ): self { $this->kind = $kind; return $this; } public function getStacksOfVotes() { return $this->stacksOfVotes; } public function setStacksOfVotes( ?StackOfVotes $stacksOfVotes ): self { $this->stacksOfVotes = $stacksOfVotes; return $this; } /** * @return Collection|Comment[] */ public function getComments(): Collection { return $this->comments; } public function getTitle(): ?string { return $this->title; } public function setTitle( string $title ): self { $this->title = $title; return $this; } public function getDescription(): ?string { return $this->description; } public function setDescription( string $description ): self { $this->description = $description; return $this; } public function getCreatedAt(): ?DateTimeInterface { return $this->createdAt; } public function getExpiracyDate(): ?DateTimeInterface { return $this->expiracyDate; } public function setExpiracyDate( DateTimeInterface $expiracyDate ): self { $this->expiracyDate = $expiracyDate; return $this; } public function getVotesMax() { return $this->votesMax; } public function setVotesMax( $votesMax ): self { $this->votesMax = $votesMax; return $this; } public function getChoicesMax() { return $this->choicesMax; } public function setChoicesMax( $choicesMax ): self { $this->choicesMax = $choicesMax; return $this; } public function getAllowedAnswers(): ?array { return $this->allowedAnswers; } public function setAllowedAnswers( array $allowedAnswers ): self { if ( ! count( $allowedAnswers ) ) { $this->allowedAnswers = [ 'yes' ]; } else { $this->allowedAnswers = $allowedAnswers; } return $this; } public function getVotesAllowed(): ?bool { return $this->votesAllowed; } public function setVotesAllowed( ?bool $votesAllowed ): self { $this->votesAllowed = $votesAllowed; return $this; } public function getModificationPolicy(): ?string { return $this->modificationPolicy; } public function setModificationPolicy( string $modificationPolicy ): self { $this->modificationPolicy = $modificationPolicy; return $this; } public function getHideResults(): ?bool { return $this->hideResults; } public function setHideResults( bool $hideResults ): self { $this->hideResults = $hideResults; return $this; } public function getShowResultEvenIfPasswords(): ?bool { return $this->showResultEvenIfPasswords; } public function setShowResultEvenIfPasswords( bool $showResultEvenIfPasswords ): self { $this->showResultEvenIfPasswords = $showResultEvenIfPasswords; return $this; } public function getOwner(): ?Owner { return $this->owner; } public function setOwner( ?Owner $owner ): self { $this->owner = $owner; return $this; } public function getPassword(): ?string { return $this->password; } public function setPassword( string $password ): self { $this->password = md5( $password ); return $this; } public function getAdminKey(): ?string { return $this->adminKey; } public function setAdminKey( string $adminKey ): self { $this->adminKey = $adminKey; return $this; } public function getId(): ?int { return $this->id; } public function findChoiceById( int $id ) { $choices = $this->getChoices(); $counter = 0; // there must be something cleaner than this in Doctrine ArrayCollection foreach ( $choices as $choice ) { $counter ++; if ( $counter > $this->maxChoicesLimit ) { throw new ErrorException( "max number of choices reached for this poll" ); } if ( $choice && $choice->getId() == $id ) { return $choice; } } return null; } /** * @return Collection|Vote[] */ public function getVotes(): Collection { return $this->votes; } public function getCustomUrl(): ?string { return $this->customUrl; } public function setCustomUrl( string $customUrl ): self { $this->customUrl = $customUrl; return $this; } public function getMailOnComment(): ?bool { return $this->mailOnComment; } public function setMailOnComment( bool $mailOnComment ): self { $this->mailOnComment = $mailOnComment; return $this; } public function getMailOnVote(): ?bool { return $this->mailOnVote; } public function setMailOnVote( bool $mailOnVote ): self { $this->mailOnVote = $mailOnVote; return $this; } public function addComment( Comment $comment ): self { if ( ! $this->comments->contains( $comment ) ) { $this->comments[] = $comment; $comment->setPoll( $this ); } return $this; } public function removeComment( Comment $comment ): self { if ( $this->comments->contains( $comment ) ) { $this->comments->removeElement( $comment ); // set the owning side to null (unless already changed) if ( $comment->getPoll() === $this ) { $comment->setPoll( null ); } } return $this; } public function addStackOfVote( StackOfVotes $stackOfVote ): self { if ( ! $this->stacksOfVotes->contains( $stackOfVote ) ) { $this->stacksOfVotes[] = $stackOfVote; $stackOfVote->setPoll( $this ); } return $this; } public function removeStackOfVote( StackOfVotes $stackOfVote ): self { if ( $this->stacksOfVotes->contains( $stackOfVote ) ) { $this->stacksOfVotes->removeElement( $stackOfVote ); // set the owning side to null (unless already changed) if ( $stackOfVote->getPoll() === $this ) { $stackOfVote->setPoll( null ); } } return $this; } public function addVote( Vote $vote ): self { if ( ! $this->votes->contains( $vote ) ) { $this->votes[] = $vote; $vote->setPoll( $this ); } return $this; } public function removeVote( Vote $vote ): self { if ( $this->votes->contains( $vote ) ) { $this->votes->removeElement( $vote ); // set the owning side to null (unless already changed) if ( $vote->getPoll() === $this ) { $vote->setPoll( null ); } } return $this; } public function addTextChoiceArray( array $choiceTextArray ): self { foreach ( $choiceTextArray as $text ) { $newChoice = new Choice(); $newChoice->setName( $text ); $this->addChoice( $newChoice ); } return $this; } public function addChoice( Choice $choice ): self { if ( ! is_null( $this->choices ) ) { if ( ! $this->choices->contains( $choice ) ) { $this->choices[] = $choice; $choice->setPoll( $this ); } } else { $this->choices[] = $choice; $choice->setPoll( $this ); } return $this; } public function addStacksOfVote( StackOfVotes $stacksOfVote ): self { if ( ! $this->stacksOfVotes->contains( $stacksOfVote ) ) { $this->stacksOfVotes[] = $stacksOfVote; $stacksOfVote->setPoll( $this ); } return $this; } public function removeStacksOfVote( StackOfVotes $stacksOfVote ): self { if ( $this->stacksOfVotes->contains( $stacksOfVote ) ) { $this->stacksOfVotes->removeElement( $stacksOfVote ); // set the owning side to null (unless already changed) if ( $stacksOfVote->getPoll() === $this ) { $stacksOfVote->setPoll( null ); } } return $this; } public function removeChoice( Choice $choice ): self { if ( $this->choices->contains( $choice ) ) { $this->choices->removeElement( $choice ); // set the owning side to null (unless already changed) if ( $choice->getPoll() === $this ) { $choice->setPoll( null ); } } return $this; } public function getCommentsAllowed(): ?bool { return $this->commentsAllowed; } public function setCommentsAllowed( ?bool $commentsAllowed ): self { $this->commentsAllowed = $commentsAllowed; return $this; } public function getIsZeroKnowledge(): ?bool { return $this->isZeroKnowledge; } public function setIsZeroKnowledge( ?bool $isZeroKnowledge ): self { $this->isZeroKnowledge = $isZeroKnowledge; return $this; } }