开发者

Help dealing with a complex mixture of dependencies, sorting, filtering, and access control

I've been wrestling with this code for a while, trying to clean it up but it just doesn't feel right. I have a Model, called Library. Libraries can own books, and the Library Model class has a public books property which is simply an array of Books. The model might look something like this:

Application_Model_Library {
    public $books = null;

    protected $_id;
    protected $_name;

    /* Getters, setters, etc. */
}

I also have a Book model. Users can have access to Books which is defined by a many-to-many table, users_books_permissions.

The library model stores the number of books the current user has access to, which is found using a JOIN on the books table and COUNT(*). Obviously, the library table itself doesn't store this information, so it is a calculated field.

protected $_accessibleBookCount;

All of my models are contained in one file, with (static) mappers built it. For example:

// In the Application_Model_Library class
publi开发者_开发知识库c static function fetchAll(){
    $db = Zend_Registry::get("db");
    /* etc */
}

However, my pagination plugin needs access to the raw select statement so it can add the LIMIT clause. This is also useful for sorting and filtering. To handle this, fetching a list of books actually requires two calls. The first one creates and returns a select object. This is modified in my controller based on the parameters to add sorting, filtering, and paginating. Then, another method in my Model takes the select object and performs the actual fetching and initialing of objects.

The first method is also responsible for injecting the JOIN that populates the $_accessibleBookCount field.

Fetching a single Library involves getting the select statement from the aforementioned function, adding a WHERE clause so only the library I want is selected, and then feeding this into the method to actually instantiate the Library model object.

Once I have a library object, fetching its books is handled by a method in the Library model called getBooks. If $books is null, then the method populates it. Then, the array is returned. Access to individual books can be achieved because the $books property is public. Upon fetching, the method also uses a JOIN to determine whether the user has access to the book.

However, what if I need to fetch a list of all libraries AND list each library's books at the same time? It's two method calls to get the list of libraries, but then getBooks must be called on each Library. This results in A LOT of repeated queries.

Whew. I want to thank anyone who was able to hold on long enough to get to the end of my post. I'd also like to thank anyone ahead of time for their help.


The only solution I see to fetch all books and libraries in one query is to actually fetch for all books and join with the libraries table. This might or might not be a better solution depending on what you are doing with libraries and books in your program.

Something like this (in Books model):

$select = $this->select();
$select->setIntegrityCheck(false)
       ->from(array("b" => "books"))
       ->join(array("l" => "libraries"),"b.lid = l.id",array("libraryName" => "l.name")) // lid = Library ID in Books table
       ->order("l.name ASC"); // Order by Library Name

You could then do some PHP magic to sort out Libraries and Books (create new objects,arrays, or whatever you want), for instance:

$libraries = array(); 
foreach($books as $book) {
  $libraries[$book->libraryName]["books"][] = $book; 
}

You have to see if it's worth the trouble and is faster/more efficient than SQL queries.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜