CodeIgniter Forums
DataMapper ORM v1.8.0 - Printable Version

+- CodeIgniter Forums (https://forum.codeigniter.com)
+-- Forum: Archived Discussions (https://forum.codeigniter.com/forumdisplay.php?fid=20)
+--- Forum: Archived Libraries & Helpers (https://forum.codeigniter.com/forumdisplay.php?fid=22)
+--- Thread: DataMapper ORM v1.8.0 (/showthread.php?tid=37531)



DataMapper ORM v1.8.0 - El Forum - 03-31-2011

[eluser]cladff[/eluser]
I found it Smile

u forgot someting in _moveSubtree i think

i changed it to

Code:
private function _moveSubtree($object, $node, $destination_id)
    {
        // if we have multiple roots
        if ( in_array($this->_rootfield, $object->fields) )
        {
            // make sure both nodes are part of the same tree
            if ( $object->{$this->_rootfield} != $node->{$this->_rootfield} )
            {
                return FALSE;
            }
        }

        // determine the size of the tree to move
        $treesize = $object->{$this->_rightindex} - $object->{$this->_leftindex} + 1;

        // get the objects left- and right pointers
        $left_id = $object->{$this->_leftindex};
        $right_id = $object->{$this->_rightindex};
        
        // shift to make some space
        $this->_shiftRLValues($node, $destination_id, $treesize);
        
        if($object->{$this->_leftindex} >= $destination_id)
        {
            $left_id+=$treesize;
            $right_id+=$treesize;
        }
        
        // enough room now, start the move
        $this->_shiftRLRange($node, $left_id, $right_id, $destination_id - $left_id);

        // and correct index values after the source
        $this->_shiftRLValues($object, $right_id + 1, -$treesize);

        // return the object
        return $object->get_by_id($object->id);
    }

(i added)
Code:
if($object->{$this->_leftindex} >= $destination_id)
{
      $left_id+=$treesize;
      $right_id+=$treesize;
}

and it worked i think... i'll test more but first appears good!

EDIT: And it seems it corrects the make_previous_sibling_of issue!

Smile


DataMapper ORM v1.8.0 - El Forum - 04-01-2011

[eluser]WanWizard[/eluser]
Cool!

Thanks for your efforts. Let me know if this remains stable for you.


DataMapper ORM v1.8.0 - El Forum - 04-05-2011

[eluser]ipsod[/eluser]
I've got something weird going on with DataMapper Sad.


I'm updating an entry with custom validation. If I mess up another field, for example, put text in a 'numeric' validation field, the custom validation function gets called. Otherwise, it doesn't. Seemingly, 'unique' doesn't get called, either, because no error is thrown.


*UPDATE*
Never mind. It wasn't getting called because the field wasn't required. Easy fix.


DataMapper ORM v1.8.0 - El Forum - 04-05-2011

[eluser]WanWizard[/eluser]
What is 'unique'? Where did you define this method? What's the code?

*UPDATE* ok Smile


DataMapper ORM v1.8.0 - El Forum - 04-11-2011

[eluser]rherriman[/eluser]
I'm running into issues with subqueries and method chaining. I'm using DM from TIP, which I needed to resolve issue #32, which seemingly affected subqueries in general. I'm also using the nested sets extension for a site's category hierarchy. Here's some sample code.

Code:
class Category extends DataMapper {
    public $default_order_by = array('left_id');
    public $extensions = array('nestedsets');

    public function or_where_depth($level) {
        return $this->or_where_subquery(intval($level), $this->_depth_subquery());
    }

    public function select_depth($alias = 'depth') {
        return $this->select_subquery($this->_depth_subquery(), $alias);
    }

    public function where_depth($level) {
        return $this->where_subquery(intval($level), $this->_depth_subquery());
    }

    /**
     * Builds and returns a subquery that calculates node depth.
     */
    protected function _depth_subquery() {
        return $this->get_clone()
            ->select_func('COUNT', '@id', 'depth')
            ->where('${parent}.left_id > left_id AND ${parent}.left_id < right_id');
    }
}

Now the scenario: I want to write a single query that gives me every category at node depth 1 OR 2, ordered by left_id, with the depth of the node being included in the SELECT statement. This way, I can loop through the output in order and build a nested unordered list. If the node has a depth of 1, it is a parent in the context of this list, and the following nodes of depth 2 are its children, until it hits another node with a depth of 1. The DM query I tried building looks like this:

Code:
$category_list = new Category();
$category_list->select_depth()->where_depth(1)->or_where_depth(2)->order_by('left_id')->get();

Here is the query it generates:

Code:
SELECT (SELECT COUNT(`categories_subquery`.`id`) AS depth
FROM `categories` `categories_subquery`
WHERE `categories`.`left_id` > left_id AND categories.left_id < right_id) AS depth
FROM (`categories`)
WHERE 1 =(SELECT (SELECT COUNT(`categories_subquery`.`id`) AS depth
     FROM `categories` `categories_subquery` `categories_subquery`
     WHERE `categories_subquery`.`left_id` > left_id AND `categories_subquery`.left_id < right_id) AS depth, COUNT(`categories_subquery`.`id`) AS depth
    FROM `categories` `categories_subquery`
    WHERE `categories`.`left_id` > left_id AND categories.left_id < right_id)
OR 2 =(SELECT (SELECT COUNT(`categories_subquery`.`id`) AS depth
     FROM `categories` `categories_subquery` `categories_subquery`
     WHERE `categories_subquery`.`left_id` > left_id AND `categories_subquery`.left_id < right_id) AS depth, COUNT(`categories_subquery`.`id`) AS depth
    FROM `categories` `categories_subquery`
    WHERE 1 =(SELECT (SELECT COUNT(`categories_subquery`.`id`) AS depth
         FROM `categories` `categories_subquery` `categories_subquery` `categories_subquery`
         WHERE `categories_subquery`.`left_id` > left_id AND `categories_subquery`.left_id < right_id) AS depth, COUNT(`categories_subquery`.`id`) AS depth
        FROM `categories` `categories_subquery` `categories_subquery`
        WHERE `categories_subquery`.`left_id` > left_id AND `categories_subquery`.left_id < right_id)
    AND `categories`.`left_id` > left_id AND categories.left_id < right_id)
ORDER BY `categories`.`left_id`

This is quite hard to parse, but hopefully it is apparent what is going on. The chaining is causing all previously called subqueries to be included in subsequent subqueries. Note the table name aliasing:

Code:
...FROM `categories` `categories_subquery` `categories_subquery` `categories_subquery`...

Is this a bug in DataMapper itself, or am I simply missing something? Suggested fixes?

Thank you.


DataMapper ORM v1.8.0 - El Forum - 04-11-2011

[eluser]WanWizard[/eluser]
It not a bug, it's a lack of this feature. Smile

Datamapper only supports one sub-query per table, the alias is created hardcoded as {tablename}_subquery. Besides that, you're subqueries look very funny. Don't think all this repeating of 'depth', nor the AS in the WHERE clauses, are supposed to be there.

But, it's your looking for output so you can generate an (indented) list, why not simply use dump_tree()? That's what it's there for. Dump it into an array. It will contains extra fields, like '__path' (the flattened path to the node) and '__level' (the depth level). It uses the current loaded node as root of the tree to dump (so you can dump subtrees).


DataMapper ORM v1.8.0 - El Forum - 04-11-2011

[eluser]rherriman[/eluser]
That's always an option of course, and I could have achieved similar results simply by keeping the select_depth() method and not filtering the results at all (among other solutions). However, this is not always desirable. In this particular instance, I have nodes as deep as five levels, and only need to retrieve two tiers. That's (potentially) a lot of extra data pulled from SQL unnecessarily that PHP will in turn have to loop all the way through. Granted most trees will not be very large, but still.

This behavior still seems incorrect. Shouldn't multiple subqueries be allowed? So long as they are "siblings," at least. I understand the issue with implementing nested subqueries. Smile


DataMapper ORM v1.8.0 - El Forum - 04-11-2011

[eluser]WanWizard[/eluser]
The problem with subqueries is that you create them as separate objects, so they are not aware of each others existance. By the time the query is assembled, all aliases are already in place...

As for your consideration: dump_tree() runs a fairly simple query. Yes, it might return too much data, but as you said trees don't tend to be that large, and running a query with lots of subqueries isn't exactly cheap either...


DataMapper ORM v1.8.0 - El Forum - 04-11-2011

[eluser]rherriman[/eluser]
I thought the isolated nature of subqueries would have allowed me to generate a query that looked something like this:

Code:
SELECT *, {depth subquery} AS depth
FROM categories
WHERE
    1 = {depth subquery} OR
    2 = {depth subquery}
ORDER BY left_id

This is particularly expected given that my _depth_subquery method returns a subquery run first through get_clone. I feel like each time I call that method it should be building a new subquery, but I guess the issue is that the subquery itself is being copied by get_clone as well. Hmmmm. Perhaps a method to clear subqueries would be useful? Not sure what other situations exist where it would be useful, but I could envision something similar to $this->get_clone()->clear_subquery()->{query}_subquery($param1, $param2) solving the issue. Or even an alternative to get_clone that simply ignores the subquery state. Whichever was less disgusting. Smile

Actually, would calling the clear method after get_clone work and give me a fresh query slate to work from?


DataMapper ORM v1.8.0 - El Forum - 04-11-2011

[eluser]WanWizard[/eluser]
get_clone() does exactly that, it creates a clone. With everything in it, including the state of $this->db.

To be honest, I haven't spent a lot of time on subqueries, so for me it's trial and error too. And I don't have a lot of trail time at the moment, due to other commitments (including the one with the mrs to get some bread on the table Wink).