Modifying YiiMongoDBSuite for a specific schema

I’m building a webapp with MongoDB. I would love to use YiiMongoDbSuite because it is very well programmed and has many features I could use :)

But I need to modify/ extend YiiMongoDbSuite for my own application. I need two big modifications.

1. Localization

I use a schema like described here on Stack Overflow: http://goo.gl/uItT8

When the object contains:




multi_language_attributes:["name"],

name:{

	description:{

		en: "Name",

		nl: "Naam"

	},

	value:{

		en: "Super fast car",

		nl: "Hele snelle auto"

	}

}

I want to access this like $product->name->description. The locale ("en" or "nl") is available to the model off course.

2. Schema less design

With YiiMongoDBSuite you need to define all attributes as public properties or return them in an array with the getAttributes() function. But I want to make use of the schema-less property of MongoDB.

I don’t want to define all attributes upfront in the model. The user should be able to insert his own (multi-language) attributes into the MongoDB document. Then he should be able to access the attribute in the app’s view like this: $model->userDefinedAttribute. When the userDefinedAttribute is not found, nothing is returned.

[size="5"]The Question: How does YiiMongoDbSuite work?[/size]

I know basically how it works, but I don’t understand it’s inner workings good enough to implement both modifications properly. Especially the part with $_embedded, setAttributes(…) and the __get and __set functions is very unclear to me.

I’m working a lot with YiiMongDbSuite and the mongoDB.

My expirience:

  1. YiiMongDbSuite is great and saves a lot of work when you need models and UI for CRUD operations

  2. YiiMongDbSuite is slow for other operations because of always have to generate the activerecord models after find, on insert, update, delete. That’s a problem of using activrecords for other databases too.

  3. You should mix: direct calls to the mongoDB and models

For example:

My BaseModel (extends EMongoDocument) has a method ‘atomicUpdate’ for atomic updating values without loading the full model from db, change values and update all.




public function atomicUpdate($criteria,$values,$modifier = '$set', $multiple = false, $options=array())

	{

		if (empty($values))

			return false;


		$action = array($modifier => $values);

		$options = $multiple ? array_merge($options,array('multiple'=>true)) : $options;


		return $this->getCollection()->update($criteria,$action,$options);

	}



Usage:




   

  MyModel::model()->atomicUpdate(

             array('_id'=>new MongoId($id),

             array('status'=>1,....)

     );




  1. 2 solutions, if you want to make use of the schema-less property of MongoDB
  • Use Soft Documents Models

    from the YiiMongDbSuite.

  • My prefered solution:

My BaseModel (extends EMongoDocument) has a attribute ‘data’.

YiiMongDbSuite can only see this public property and loads and saves it ‘as it is’.

So you can store all what you want (array …) within this property.

You can save/update your structure from above like data[‘languages’]=array(…your language structure …)

Take a look at the code of the first release of my mongocms

I have changed a lot since this release, but maybe you find some ideas about mixing direct calls to the mongoDB and YiiMongDbSuite.

Thanks for the tips Joblo. Mongocms is a nice project, I will have a look at it :)