php 与学说的一对一关系

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了php 与学说的一对一关系相关的知识,希望对你有一定的参考价值。

<?php

// namespace ...

/**
 * Class VineAccess
 *
 * Represent an Access over a Vine
 *
 * @ORM\Entity
 */
class VineAccess extends AbstractAccess
{
    const SCOPE_PRODUCER = 'SCOPE_VINE_PRODUCER';
    const SCOPE_DRINKER = 'SCOPE_VINE_DRINKER';
    
    /**
     * @var Beer
     *
     * @ORM\ManyToOne(targetEntity="...\Entity\Vine")
     */
    protected $object;

    /**
     * @param User   $user     
     * @param string $scope A vine scope (constant)
     * @param Vine   $beer  The Beer to be secured
     */
    public function __construct(User $user, $scope, Vine $vine)
    {
        parent::__construct($user, $scope);
        $this->object = $vine;
    }

    /**
     * {@inheritdoc}
     * 
     * @return AbstractContract
     */
    public function getObject()
    {
        return $this->object;
    }
    
} 
<?php

// namespace ...

/**
 * Class UpdateSchemaCommand
 *
 * This command is a hack for the Doctrine Schema Tool.
 * Actually the Access classes use a one-to-ANY (different target entities per sub classes).
 *
 * While the entity manager is able to deal with this schema thanks to the single-table inheritance
 * The schema tool doesn't understand this architecture.
 *
 * Only for this command, we add a special listener (AccessSchemaListener)
 * which fakes a simple integer column instead of an association
 */
class UpdateSchemaCommand extends UpdateSchemaDoctrineCommand
{
    public function configure()
    {
        parent::configure();

        $this->setName('...:schema:update');
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $evm = $this->getApplication()->getKernel()->getContainer()->get('doctrine')->getManager()->getEventManager();
        $evm->addEventListener(Events::loadClassMetadata, new AccessSchemaListener());

        parent::execute($input, $output);
    }
} 
<?php

// namespace ...

/**
 * Class BeerAccess
 *
 * Represent an Access over a Beer
 *
 * @ORM\Entity
 */
class BeerAccess extends AbstractAccess
{
    const SCOPE_BARTENDER = 'SCOPE_BEER_BARTENDER';
    const SCOPE_CUSTOMER = 'SCOPE_BEER_CUSTOMER';
    
    /**
     * @var Beer
     *
     * @ORM\ManyToOne(targetEntity="...\Entity\Beer")
     */
    protected $object;

    /**
     * @param User   $user     
     * @param string $scope A Beer scope (constant)
     * @param Beer   $beer  The Beer to be secured
     */
    public function __construct(User $user, $scope, Beer $beer)
    {
        parent::__construct($user, $scope);
        $this->object = $beer;
    }

    /**
     * {@inheritdoc}
     * 
     * @return AbstractContract
     */
    public function getObject()
    {
        return $this->object;
    }
    
} 
<?php
 
 // namespaces ...

/**
 * Class AccessSchemaListener
 *
 * This listener is used with the Doctrine Schema Tool
 * It fakes a simple integer doctrine column instead of an association:
 *
 * - it removes all association to each secured object in the sub access classes (BeerAccess, SodaAccess...)
 * - it adds a mapping on the parent/root abstract class AbstractAccess
 * - it adds an indexe on this emulated integer column
 */
class AccessSchemaListener
{
    public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs)
    {
        $classMetadata = $eventArgs->getClassMetadata();

        if ($classMetadata->rootEntityName === '...\\Entity\\Security\\AbstractAccess') {
            if ($classMetadata->name === '...\\Entity\\Security\\AbstractAccess') {
                // For the AbstractAccess:
                // - fake a simple integer column on AbstractAccess::$object (that's why we need the protected object declaration)
                $classMetadata->fieldMappings['object'] = [
                    'fieldName' => 'object',
                    'type' => 'integer',
                    'scale' => 0,
                    'length' => null,
                    'unique' => false,
                    'nullable' => false,
                    'precision' => 0,
                    'columnName' => 'object_id'
                ];
                
                // - keep the existing SQL index used for the foreign key
                if (!isset($classMetadata->table['indexes'])) {
                    $classMetadata->table['indexes'] = [];
                }
                $classMetadata->table['indexes']['IDX_1C52E62232D562B'] = ['columns' => ['object_id']];
                
            } else {
                // For the access subclasses: remove the association
                unset($classMetadata->associationMappings['object']);
            }
        }
    }
}
<?php

// namespace ...

/**
 * Abstract class access
 *
 * Represent any access for a user on a resource
 *
 * @ORM\Entity(repositoryClass="...\Entity\Security\AccessRepository")
 * @ORM\InheritanceType("SINGLE_TABLE")
 * @ORM\DiscriminatorColumn(name="object_type", type="string")
 * @ORM\DiscriminatorMap({
 *      "...\Entity\BeerClass"       = "...\Entity\Security\BeerAccess",
 *      "...\Entity\WaterClass"               = "...\Entity\Security\WaterAccess",
 *      "...\Entity\SodaClass" = "...\Entity\Security\SodaAccess"
 * })
 */
abstract class AbstractAccess implements AccessInterface
{
    /**
     * @var int
     *
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var DateTime
     *
     * @ORM\Column(type="date")
     * @Assert\NotNull()
     * @Assert\Date()
     */
    private $grantedAt;

    /**
     * @var string
     *
     * @ORM\Column(type="string")
     * @Assert\NotNull()
     */
    private $scope;

    /**
     * @var \...\UserBundle\Entity\User
     *
     * @ORM\ManyToOne(targetEntity="...\UserBundle\Entity\User")
     */
    private $user;

    /**
     * @var object The secured object
     *
     * We do not map doctrine association here to the secured object
     * because the single-table inheritance doesn't support different types for a relation
     * Since we need to secure different object types (beer, vine, soda...) the association is defined in the sub classes
     *
     * Yet we need this property to avoid doctrine schema tool to throw some exception on the update command
     * @see AccessSchemaListener which is an hack for the schema tool
     */
    protected $object;

    /**
     * @param User   $user
     * @param string $scope
     */
    public function __construct(User $user, $scope)
    {
        $this->user      = $user;
        $this->scope     = $scope;
        $this->grantedAt = new DateTime();
    }

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

    /**
     * @return \DateTime
     */
    public function getGrantedAt()
    {
        return $this->grantedAt;
    }

    /**
     * @return string
     */
    public function getScope()
    {
        return $this->scope;
    }

    /**
     * @return \...\UserBundle\Entity\User
     */
    public function getUser()
    {
        return $this->user;
    }
}

以上是关于php 与学说的一对一关系的主要内容,如果未能解决你的问题,请参考以下文章

学说:具有复合键的实体之间的 ManyToX 关系

Symfony2 和空关系的学说

跨数据库关系学说2和PHP

Symfony 2 与 Doctrine 中的一对多关系

php 一对一关系与反向关系

与复合唯一约束的关系(symfony + 学说)