简体   繁体   中英

Symfony2/Doctrine2 database relationship between a group, a message and a location

I'm trying to come up with the right model for the relationship between a Group of users, a short displayed alert Message, and a named Location.

For example: Students and Interns ( Groups ) might need a special instruction ( Message ) to be displayed at the top of a page ( Location ), while Teachers and Teammanagers might need to see a different string of text.

  • A location can have multiple messages, but only one per group.
  • A group can have multiple messages, but only one per location.
  • Multiple groups (thousands, in some cases) can be assigned the same identical message, so Message as an entity with keys to location & group would cause a lot of duplication.
class Message {

    /**
     * @ORM\ManyToOne(targetEntity="...Bundle\Entity\Group", inversedBy="messages")
     * @ORM\JoinColumn(name="group_id", referencedColumnName="id", nullable=false)
     */
    protected $groups;

    /**
     * @ORM\ManyToOne(targetEntity="...Bundle\Entity\Location", inversedBy="messages")
     * @ORM\JoinColumn(name="location_id", referencedColumnName="id", nullable=false)
     */
    protected $location;
}

I feel like there should be a Many-to-one relation between Messages and a Location, and a Many-to-one relation between groups and some combined "Message+Location" entity.

I'm having trouble setting up entities in this way though.

With your schema, you can do something like that :

class Message {

    /**
     * @ORM\ManyToMany(targetEntity="...Bundle\Entity\Group", inversedBy="messages")
     * @ORM\JoinColumn(name="group_message"
     * joinColumns={@ORM\JoinColumn(name="group_id", referencedColumnName="id")},
     * inverseJoinColumns={@ORM\JoinColumn(name="message_id", referencedColumnName="id")})

     */
    protected $groups; //Here, a group can have many messages and a messages can be attached at many groups so => manyToMany

    /**
     * @ORM\ManyToOne(targetEntity="...Bundle\Entity\Location", inversedBy="messages")
     * @ORM\JoinColumn(name="location_id", referencedColumnName="id", nullable=false)
     */
    protected $location; //[1] Message can have One location and location can have many messages in the case of messages at the same location are not assigned at the same group.
}

class Location {

    /**
     * @ORM\OneToMany(targetEntity="...Bundle\Entity\Message", mappedBy="location")
     * @ORM\JoinColumn(name="message_id", referencedColumnName="id", nullable=false)
     */
    protected $messages;

}

class Group {

    /**
     * @ORM\ManyToMany(targetEntity="...Bundle\Entity\Message", mappedBy="groups")
     */
    protected $messages;

}

To ensure the [1] condition, you can make a callback in your Message entity. This callback will check, when you're inserting a Message that a group doesn't have an another message at the same location.

To do a callback, here the doc is :

/**
 * @Assert\Callback({"Vendor\Package\Validator", "validate"})
 */
class Message {
    [...]
    public function validate(ExecutionContextInterface $context)
    {

        // check if the location is already used for one of the group on $this (entity returned by the form)
        foreach($this->getGroups() as $group) {

            foreach($group->getMessages as $message) {

                if ($this->getLocation() == $message->getLocation()) {

                    $context->buildViolation('Location already used!')
                            ->atPath('location')
                            ->addViolation();
                }
            }
        }
            // If you're using the old 2.4 validation API
            /*
            $context->addViolationAt(
                    'location',
                    'Location already used!'
                    );
            */
        }
    }
}

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