views:

48

answers:

3

Hi,

I have models that extend Doctrine_Record, and are directly mapped to one specific record from the database (that is, one record with given a given id, hardcoded statically in the class).

Now, I want the specific record class to initialize itself as if Doctrine_Query would. So, this would be the normal procedure:

$query = new Doctrine_Query();
$model = $query->from('Model o')->where('id = ?', 123)->fetchOne();

I would like to do something like this

$model = new Model();

And in the Model:

const ID = 123;

//note that __construct() is used by Doctrine_Record so we need construct() without the __
public function construct()
{
    $this->id = self::ID;
    //what here??
    $this->initialize('?????');
}

So for clarity's sake: I would like the object to be exactly the same as if it would be received from a query (same state, same attributes and relations and such).

Any help would be greatly appreciated: thank you.

A: 

I don't think a model instance could decide to hang on a certain database entry after it has been initialized. That said, you can do something like this:

<?php
class Model extends baseModel {
  public static function create($id = null)
  {
    if ($id === null) return new Model;
    return Doctrine::getTable('Model')->findeOneById($id);
  }
}

And then, you can either use

$newModel = Model::create();

Or fetch an existing one having ID 14 (for example) using

$newModel = Model::create(14);

Or, if you want your 123 to be default instead of a new item, declare the function like this:

  public static function create($id = 123)
Pelle ten Cate
The trouble is, every entry (model) has different methods, variables and so on. This way, I would require to keep a `$id` outside every entry (model) to allow initialization.
No, you don't have to. If all your database tables have an 'id' field, all your models will have an 'id' property. If not all your tables' primary keys are called `id`, you will have to use `$this->identifier()` to figure out the name of the PK. Alternatively, you can create a class that extends Doctrine_Record, make your models inherit that class. Then, implement that function there, replacing `'Model'` (in my code example) with `get_class($this)`.
Pelle ten Cate
If you auto-generate the models using Doctrine, use the 'baseClassName' option to make your base models extend your custom class.
Pelle ten Cate
You are assuming I have multiple tables, but i have multiple records, where each model represents a record. For example, if I have the table 'verhicles', with records 1:car,value1,value2,value3 2:bicycle,value1,value2,value3. I have models Model_Verhicle_Car, Model_Verhicle_Bicycle, which extend Model_Verhicle
And then: new Model_Verhicle_Car(); should autoload all it's properties from the database.
Ah, I didn't understand. Creating a class just for a specific record is just not the way ORM works. In ORM all the records in a certain table should be of the same type, to distinguish between the records, you could add specific database fields. There are always exceptions, but generally hard-coding IDs inside source code is a bad idea. Now the real question: if you really want to have a class that holds data in one pre-specified record, why not put the information in the class itself rather than in the database?
Pelle ten Cate
Since some of properties need to be configurable :)
Fair enough, Still, I'd use a specific `config` table in my database that holds all the configurable information using key-value pairs, and a 'class' field for the class a configuration belongs to. The Config model then would have a function `loadConfig($className)` returning all config for a class. Then, the Vehicle class (which may or may not be a Doctrine_Record at all) has different subclasses (e.g. Bicycle, Car and Bus) that should implement an interface called 'HasConfiguration', that requires a private static function `getConfig()` that should call `Config::loadConfig(__CLASS__)`.
Pelle ten Cate
Good thinking (thanks for that), though i prefer the Aggregate Column inheritance solution.
+1  A: 

Although having multiple classes for the same data type (i.e. table) is really not what ORM should be like, what you want can be done in Doctrine using Column aggregation inheritance. Assuming you are using Doctrine 1.2.x, you can write the following YML:

Vehicle:
  columns:
    brand: string(100)
    fuelType: string(100)

Car:
  inheritance:
    extends: Entity
    type: column_aggregation
    keyField: type
    keyValue: 1

Bicycle:
  inheritance:
    extends: Entity
    type: column_aggregation
    keyField: type
    keyValue: 2

Now, the Vehicle table will have a 'type' column, that determines the class that Doctrine will instantiate when you select a vehicle. You will have three classes: Vehicle, Car and Bicycle. You can give every class their own methods etc, while the records their instances represent reside in the same database table. If you use $a = new Bicycle, Doctrine automatically sets the type for you so you don't have to take care of that.

Pelle ten Cate
It's less close to what I was searching for, but you provided the most correct solution for what I am doing. For this I will award you the bounty.
+1  A: 

The first thing I need to say is I'd put the constant in the class. So like this:

class Application_Model_Person
{
    const ID = 1234;
}

Then, a Doctrine method like Doctrine_Record::fetchOne() is always returning a (new) instance of the model and never merges the data with the record you're calling fetchOne() to. Doctrine is nevertheless able to merge a retreived record with another class, so it rather simple to do:

class Application_Model_Person extends Doctrine_Record_Abstract
{
    const ID = 1234;

    public function __construct($table = null, $isNewEntry = false)
    {
        // Calling Doctrine_Record::__construct
        parent::__construct($table, $isNewEntry);

        // Fetch the record from database with the id self::ID
        $record = $this->getTable()->fetchOne(self::ID);
        $this->merge($record);
    }
}

Then you're able to do:

$model = new Application_Model_Person;
echo $model->id; // 1234
Jurian Sluiman
This answer is closest to my question: for this I will accept this as the answer.