Skip to content

Instantly share code, notes, and snippets.

@vjandrea
Last active December 24, 2015 16:09
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vjandrea/6825675 to your computer and use it in GitHub Desktop.
Save vjandrea/6825675 to your computer and use it in GitHub Desktop.
Example in procedural code for a tree parser based on an array that i'd like to implement in ClosureTable It echoes the code that should be executed once implemented.
<?php
$data = [
[ 'id' => 0 ],
[ 'id' => 1 ],
[ 'id' => 2,
'children' => [
[ 'id' => 3 ],
[ 'id' => 4,
'children' => [
[ 'id' => 5 ],
],
],
],
],
];
function createFromArray($data = array(), $parent = null)
{
$last_id = $parent;
foreach($data as $key => $value)
{
if($key == 'id' && !is_array($value))
{
$last_id = $value;
if($parent != null)
{
// A parent is set, we can perform the moves
echo '$page = Page::find('.$value.')'."\n";
echo '$page->moveTo('.$parent.')'."\n";
}
}
elseif($key == 'children' && is_array($value) && !is_null($parent))
{
// A parent is set, we parse the subtree
createFromArray($value, $last_id);
}
elseif(is_array($value) && count($value))
{
// Key is not id nor children, we're at the root of the array
createFromArray($value, $last_id);
}
}
}
createFromArray($data);
@kapooostin
Copy link

That's great you found time for this, thank you!

There are some questions I think we face:

  • should we replace a tree if it already exists?
  • would it be faster if we generated all the entries and then filled the whole 'closure' table?
  • do we have to search for each entity in DB before inserting corresponding entries in 'closure' table (and what do we do if the search fails)?
  • should we accept arrays as 'id' (composite keys)?

Maybe the format of a 'tree' array needs some thinking regarding the possibility of it being generated by some client-side application and sent over as JSON.

And I guess it should be put into a transaction for the sake of safety.

It is a discussion not a list of tasks :)

@vjandrea
Copy link
Author

vjandrea commented Oct 4, 2013

@kapooostin, thanks for the comments! The code above is simply a test of recursion, but actually i would like the function to be the most flexible we can achieve, a sort of "eat-all".
We have to consider that the id field is usually an auto_increment in the nodes model, so i would prefer a structure where the id is not specified and it's taken on the fly at the moment of the node creation, something like

$data = [
    [ 'name' => 'Root 1' , 'description' => 'Lorem ipsum...'],
    [ 'name' => 'Root 2' , 'description' => 'Donec etiam'],
    [ 'name' => 'Root 3', 'description' => 'Eiusque idem',
      'children' => [
        [ 'name'=> 'Child 1', 'description' => 'Yadayada'],
        [ 'name'=> 'Child 2', 'description' => 'Blabla'
          'children' => [
            [ 'name' => 'Grandchild 1', 'description' => 'Down under'],
          ],
        ],
      ],
    ],
  ];

In this way new nodes would be created, but if for example there's a unique constraint on one of the fields, we could check if it's already existing before trying to create a new node.
If, instead, the id is present in the array, then we take the existing nodes by id, update the eventually present fields with the values of the array and reposition them in the new structure. If an id doesn't exist, we may create a node with the rest of the fields of that node and replace the id present in the array with the new id. Every step then should be in a nice "try... catch" sandwich to avoid pitfalls.

@kapooostin
Copy link

I rarely use auto-incremented IDs, so my view is biased. But I guess at first we need the most common cases to be solved.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment