Question

For example, we have an external DB of Countries and Cities. We need to be able to read that external DB with the following conditions:

  1. We can't alter or modify in any way the World DB. We can't add FK for example.
  2. When using the external DB, we want to keep an internal reference, for example for our entity "User" we want to keep a reference such as User->city
  3. We want to have an internal entity CustomCities where users can create their own cities.

What would be the best approach to do this?

We have tried several options but all of them break in one way or another. One recommendation was to use a @Table with an external reference readOnly but that didn't work.

The closest solution we have found for this is to use an in-between class that represents a City object, but doesn't really hold data, and then via native queries, we populate that fake object. Then using internal logic we determine if the requested item such as User->getCity() came from the City DB or came from the CityCustomDB...

Any ideas on how to approach this?

No correct solution

OTHER TIPS

I've taken a guess at the possible schema, have you tried using Class Table Inheritance so that the country essentially becomes your interface.

Database Schema

interface CountryInterface
{
    public function getName();
}

So your entities might look like this

/**
 * @InheritanceType("JOINED")
 * @DiscriminatorColumn(name="type", type="string")
 * @DiscriminatorMap({
 *     "internal" = "InternalCountry"
 *     ,"external" = "ExternalCountryAlias"
 * })
 */
abstract class AbstractCountry implements CountryInterface
{
    protected $id;
}

class InternalCountry extends AbstractCountry
{
    protected $name;

    public function getName()
    { 
        return $this->name;
    }
}

The ExternalCountryAlias works like a proxy to ExternalCountry, but I named it Alias so not to confuse it with Data Mapper Proxies.

class ExternalCountryAlias extends AbstractCountry
{
    /**
     * @OneToOne(targetEntity="ExternalCountry")
     * @JoinColumn(name="external_country_id"
     *     ,referencedColumnName="id")
     */
    protected $externalCountry;

    public function getName()
    {
        return $this->externalCountry->getName();
    }
}

ExternalCountry doesn't have to extend from the base class.

class ExternalCountry 
{
    protected $name;

    public function getName()
    {
        return $this->name;
    }
}

So when you get a country you are referencing the base class. So lets say country.id = 1 is and internal country and country.id = 2 is an external country.

// returns an instance of InternalCountry
$entityManager->find('AbstractCountry', 1);

// returns an instance of ExternalCountryAlias 
$entityManager->find('AbstractCountry', 2); 

And because they both implement CountryInterface you don't have to worry where they came from, you still access the name by calling getName();

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top