3

I'm looking to use Lithium framework to build my application config interface as I like its minimal approach and the document-store (i.e. Mongodb) centric model.

However, (and I know its not quite released yet), there is little-to-no information, tutorials or examples out there to move you on from the simple blog tutorial.

What I am trying to do now is build an app that will show me the collections I have in Mongodb, and then let me work with which ever collection I choose. I can't seem to figure out:

a) how would I build a model that enumerates the collections - preferably according to my internal naming scheme,

b) how do I break the convention model so I can specify the name of the collection to use?

I think there are two things i'm struggling with to answer these two questions - perhaps a fundamental misunderstanding of how to move a model in MVC beyond the simple collection-model-controller-view examples, and secondly, the actual process of telling the mongo datasource what collection to use.

any pointers or examples, gratefully received.

Chris

update::

So I figured out how to set the collection - for reference you can set source in the $_meta array like this:

protected $_meta = array(
    'source' => '<<collectionName>>'
);

still no idea how to use a Model that will list me all the collections I have in my DB though. Any ideas how to do that from a philosophical and also technological manner?

further update::

so I have got a bit further thanks to the comments below. At least I might now be able to re-phrase the question a bit. I can define my model something like this:

<?php
namespace app\models;
use lithium\data\Model;

class Posts extends \lithium\data\Model{

    protected $_meta = array('source' => false);

    public function testcolls(){
        return (self::connection()->sources());
    }
}
?>

then in my view I can use:

<?php foreach ($post->testcolls() as $coll): ?>
    <h2><?=$coll ?></h2>
<?php endforeach; ?>

that works - however, what I really want to do is not create a 'testcolls' method in my Model but as Medhi suggested below, I need to override the find method. I can't seem to figure out how to do that and what it would need to return. The docs are not too clear on this.

final update

based on the comment below and a bit of experimentation, I came up with the following that works for being able to call find with a collection as a parameter.

model:

class Dataqueues extends \lithium\data\Model{

    protected $_meta = array('source' => false);

    public static function find($filter, array $options = array()) {
        if (isset($options['collection'])){
            self::meta('source', $options['collection']);
        }
        return parent::find('all',$options);
    }   
}

controller:

class DataqueuesController extends \lithium\action\Controller {

    public function index() {
        $dataqueues = Dataqueues::find('all',array('limit'=>20,'collection'=>'W501'));
        return compact('dataqueues');
    }
}

getting a model that returns a list of collections was also pretty simple in the end:

class Collections extends \lithium\data\Model{

    protected $_meta = array('source' => false);

    public static function find($filter, array $options = array()) {

        return self::connection()->sources();
    }   
}

note that the controller won't support options or filters.

Mehdi Lahmam B.
  • 2,240
  • 16
  • 22

2 Answers2

3

Nothing holds you from having a Collections Model, where you set $_meta['source'] = false to prevent Lithium from looking for a Collection in your database named collections.

In this model, you can call YourModel::connection()->sources() to list all your Mongo Collections.
Docs for sources(): http://li3.me/docs/lithium/data/source/MongoDb::sources(). Basically it calls listCollections() on a MongoDB instance http://php.net/manual/en/mongodb.listcollections.php

You can override your Model::find() method to return the list of collections, instead the list of documents, or pass the collection as a param Collections::find('all', array('conditions' => ..., 'collection' => 'foo'))... or wathever you want :-)

Lithium is designed to don't force that much on you !

botero
  • 598
  • 2
  • 11
  • 23
Mehdi Lahmam B.
  • 2,240
  • 16
  • 22
  • thanks for that - makes a lot of sense -except I can't seem to get it to work :-( $_meta['source'] = false; seems to raise a T_FUNCTION parse error, and I'm not sure how to phrase the ::connection()->sources(). I tried $colls = $this->connection()->sources(); with the same result: a parse error. Sorry if this is obvious but its all new to me.. – Chris Bartlett Apr 23 '12 at 21:20
  • still no closer - I've tried `class Test extends \lithium\data\Model{ $_meta['source'] = false; Test::connection()->sources(); }` but I just get T_FUNCTION parse errors on both lines. Obviously still missing something fundamental about how the Model works. Can you provide a simple example? – Chris Bartlett Apr 23 '12 at 23:06
  • $_meta is a protected property of your model. Ping me on IRC to help you – Mehdi Lahmam B. Apr 24 '12 at 12:35
  • That would be great - how when and where suits you best? – Chris Bartlett Apr 24 '12 at 20:23
0

First of all, Lithium follows the convention over configuration approach.

What this means:

Configuration: 'source' => '<< collectionName >>'

Convention: Name your model and your collection the same thing, the framework handles the rest.
IE: A "People" collection will have a "People" model

Second, connect to your database:

Configure your connections.php file in app\bootstrap\connections.php. I know I said convention over configuration, but you still need to let the framework know where the database is and what the login info is. For details look at the http://li3.me/docs/manual/quickstart. Here is the relevant code:

// MongoDB Connection
Connections::add('default', array('type' =>  'MongoDb', 'database' => 'blog', 'host' => 'localhost'));

Third, get data
Create a model, matching your collection name, and then in your controller, add this line:

$model = Models::all();

where model is the singular name for what you are storing in your collection, and Models is the name of your model. That is it.
If you put a break point after this line, you will see your Models collection. For more information, see http://li3.me/docs/manual/working-with-data/using-models.wiki

Finally, to pass it to your view, simply put this line of code at the end of your controller:

return compact('model', 'model2', 'model3');

where model would be what you just pulled in the third step. The models 2 and 3 that I tacked on is how you would pass any other collections you pulled.

In your view, you would just reference $model to and assume that the relevant fields are there. You don't have to worry about putting getters or setters or anything else like that. For example: if you want to show the data in $model:

foreach ($model as $aModel) {
    echo $aModel;
}

See Accessing View Variables in: http://li3.me/docs/manual/handling-http-requests/views.wiki

Hope this helps.

botero
  • 598
  • 2
  • 11
  • 23
ton.yeung
  • 4,793
  • 6
  • 41
  • 72
  • Thanks - but thats not really addressing the question(s) - In my case I firstly need to enumerate the collections in my database - which doesn't seem to follow the model used by lithium (and other MVC frameworks), and then, depending which collection I choose, I will want to display all the docs in that collection. Obviously, I can't have a Model for each collection as there might be hundreds so I need to change the collection used by the model. I'm looking to understand how situations like these two, that seem to me to break the MVC model are normally handled. – Chris Bartlett Apr 23 '12 at 09:02