Giter Club home page Giter Club logo

tree's Issues

Support invalidating or rebuilding the tree (?)

A few times, I had the need to rebuild the tree with fresh data. This can be easily done, but currently requires creating a new instance, as there is no public API for refreshing the data. Creating a new instance is simple, but if instantiation can be avoided, this is a win.

Another thought: could it be useful to enable Tree to fetch (or refetch) data instead of pushing the data into the constructor (or in some other method)?

Format question : how to remove keys?

Hi,
Thanks a lot for your wonderfull tool, it works very well. Nevertheless i have a question, after creating the tree and outputting the json hierarchical tree i have:

{
	"14": {
		"name": "2 Vous \u00eates",
		"title": "2 Vous \u00eates",
		"id": 2,
		"parent": 0,
		"children": {
			"0": {
				"name": "291 Etes-vous enceinte ?",
				"title": "291 Etes-vous enceinte ?",
				"id": 291,
				"parent": 2
			}
		}
	},
...

nevertheless, what i would like to obtain is somthing formatted like this:

{
 "name": "flare",
 "children": [
  {
   "name": "analytics",
   "children": [
    {
     "name": "cluster",
     "children": [
      {"name": "AgglomerativeCluster", "value": 3938},
      {"name": "CommunityStructure", "value": 3812},
      {"name": "HierarchicalCluster", "value": 6714},
      {"name": "MergeEdge", "value": 743}
     ]
    },
...

Is this possible ?
Thanks a lot

Add an iterator (?)

Just an idea: would an iterator – to traverse the whole tree or part of the tree – be useful, in addition to the iteration methods currently available?

"getAncestorsGeneric" fails to return the last ancestor

Since version 2.0, the method Node::getAncestorsGeneric does not return the last ancestor of the set of nodes. In version 1.5.3, the method did not exist and the original method looked like this :

    public function getAncestors($includeSelf = false)
    {
        $ancestors = $includeSelf ? array($this) : array();

        if (null === $this->parent) {
            return $ancestors;
        }

        return array_merge($ancestors, $this->parent->getAncestors(true));
    }

It works fine, since if the current node has no parent, the recursive iteration ends and the current node is returned. Since 2.0, the method getAncestors uses the method getAncestorsGeneric which looks like this :

    protected function getAncestorsGeneric(bool $includeSelf): array
    {
        if (null === $this->parent) {
            return [];
        }

        return array_merge($includeSelf ? [$this] : [], $this->parent->getAncestorsGeneric(true));
    }

This means that if the current node has no parent, an empty array will be returned instead of the current node. This is fine if $includeSelf equals false, but if I have a data set with for example 2 nodes, 1 root and 1 child, the method will ultimately return an empty array despite the fact that $includeSelf equals true at some point.

own ID as parent ID exception

My data:

    {
        "id": "moblie_prj",
        "name": "my project",
        "parent": "0"
    },

this data throw exception Node with ID $id references its own ID as parent ID

I found that Tree.php (line 188) compare of two string should be === instead of ==.

Calculate max depth

I noticed that there is a method that brings the level of the category.
Is there any way to return to the maximum depth?

Make 'parent' field configurable

I work with data sets that come from other applications that I don't/can't control. The parent field of my data is id_parent and iterating over my data and renaming the filed seems a little bit of an overkill. Can you make the parent field configurable? (As in make it possible to specify what the parent field should be called).

Get return Value or null

Node::Get

why throw an exeption and not null? I've the problem there are parents with an propertie or the propertie is unset. If I initialize it with null and call the get-method from the node I get the exeption

Best regrets

Magnus

Create tree from array of ArrayAccess objects

Looks like currenty a tree can only be built from array of arrays:

    protected function createNode($id, $parent, array $properties): Node
    {
        return new Node($id, $parent, $properties);
    }

It would be great if tree could be created from array of ArrayAccess objects.

Personally I use my own tree implementation. But now I want to switch to something modern and community driven.

I looked at nicmart/tree, but looks like it is not maintained.

This projects seems to be maintained and updating to new PHP versions, I would like to use it, but lack of described functionality prevents me from it :(

I always create trees from array of objects (just looked over my last projects - I never build a tree from array of arrays).

Bug in Tree Constructor

 public function __construct(array $data, array $options = array())
    {
        $this->options = array_change_key_case($options, CASE_LOWER);
        if (!isset($this->options['rootid'])) {
            $this->options['rootid'] = 0;
        }

        $this->build($data, $options);
    }

Your changing the case of the options index but passing down the original options , should be

 $this->build($data, $this->options);

Make customization of JSON serialization more flexible

Currently, it is required to:

  • Overwrite the node class (implement at least 1 method)
  • Overwrite the tree class (implement at least 2 methods; 1 for JSON, 1 for custom node class)

Would be nicer to get along without subclassing at all. Basic concept could be: externalize the serialization, offer several serialization strategies (and pick a default strategy which produces the same JSON as the current implementation) and make them selectable.

Motivation: see #16.

Avoid magic strings for options when building Trees

I think the project will benefit from using constants instead of magic strings when declaring options. This will allow flexibility when renaming options internally in the future, as well as avoiding all issues related to magic strings, both for people contributing to the library and those using it.

I was planning on making a PR, but I figured I should open the discussion first.

I was thinking of making a class that would looking something like this (I only added the options I'm personally using in my project):

<?php

namespace BlueM\Tree;

class Options
{
    const PARENT_KEY = 'parent';
    const ID_KEY = 'id';
    const ROOT_ID = 'rootid';
}

This would allow implementations to change like this:

         $tree = new Tree(
             $data,
             [
-                'id' => 'name',
-                'rootId' => null,
             ]
         );
         $tree = new Tree(
             $data,
             [
+                Tree\Options::ID_KEY => 'name',
+                Tree\Options::ROOT_ID => null,
             ]
         );

And the constructor method for Tree would change slightly (I don't have a diff for this because I was working locally on my vendor folder, as a proof of concept)

        if (!empty($options[Options::ID_KEY])) {
            if (!\is_string($options[Options::ID_KEY])) {
                throw new \InvalidArgumentException('Option “ID_KEY” must be a string');
            }
            $this->idKey = $options[Options::ID_KEY];
        }

This would maintain backward compatibility.

Thoughts?

Ignore parentless nodes

I get my list from an external API, and it, unfortunately, contains parentless nodes. So when building a tree, it keeps throwing an exception "Node with ID $id points to non-existent parent with ID $pid".

What's the best approach for ignoring these?

how to change object to array

how to write to array?

 BlueM\Tree\Node Object
    (
        [properties:protected] => Array
            (
                [title] => 点心/蛋糕
                [id] => 1
                [parent] => 0
            )

        [parent:protected] => BlueM\Tree\Node Object
            (
                [properties:protected] => Array
                    (
                        [id] => 0
                        [parent] => 
                    )

                [parent:protected] => 
                [children:protected] => Array
                    (
                        [0] => BlueM\Tree\Node Object

                    )

            )

Check if node has been visited

Hello, I need to check when I already visited a node when traversing through a tree. In the array of arrays that I used to create the tree I added a "visited" key to each node but when I try to update said key

$node->visited = true

the node isn't updating the value of the visited property, I don't know if this is the expected behavior and if so, is there any native way to check if the node has already been visited?

Implement JsonSerializable

Nodes (maybe also the whole tree) should include a sensible default implementation of JsonSerializable to make them JSON-serializable.

Warning: json_encode(): recursion detected

I have an error when try to use json_encode with $tree->getRootNodes()
This error can be hidden on my develop machine, but the server doesn't return nothign even error

Handle malformed data

Branched from discussion in: #22

There exists a need to provide the ability to require validation of the provided data against an expected schema. By default, this should throw a new MalformedDataException (or similar) that stores information about which data attribute was missing or was otherwise malformed (i.e. key is a string instead of int), and in what way it was missing or malformed.

Performing malformed-data error checking should be enabled by default, but easily disabled. This is necessary to maintain performance on very large data sets that you know will have the right structure, such as the results of a well-written SQL statement using PDO::FETCH_ASSOC or similar.

Here is good discussion of options to validate an array against a schema: https://stackoverflow.com/questions/4036708/how-can-i-validate-the-structure-of-my-php-arrays

// Somewhere around L216 in Tree.php, immediately inside of "foreach ($data as $rows)"
if ($this->malformedDataHandler !== false)
{
    $malformedData = array_diff(array_merge_recursive($arrCandidate, $arrModel), $arrModel));
    if (sizeof($malformedData))
    {
        call_user_func($this->malformedDataHandler, $row);
    }
}

I suggest putting it inside of the foreach so that the entire dataset doesn't have to be traversed twice. Once to get the $malformedData, if any, and then again to process it. It would be worth testing the tradeoff of checking for malformed data all at once, which would require a full re-iteration of the array, but that may end up actually being quicker than doing the array_merge_recursive() and array_diff() over every node inline.

The above suggestion would allow the user to set $malformedDataHandler = false; and disable checking/handling of the data vs the schema, and just allow PHP to log its E_NOTICE given that malformed data is encountered.

ErrorException Notice: Undefined index: parent

ErrorException
in \vendor/bluem/tree/src/Tree.php (line 235)

230 $row = iterator_to_array($row);
231 }
232 $this->nodes[$row[$this->idKey]] = $this->createNode(
233
234 $row[$this->idKey],
235 $row[$this->parentKey],
236 $row
237 );
238
239 if (empty($children[$row[$this->parentKey]])) {
240
erreur Bluem tree
$children[$row[$this->parentKey]] = [$row[$this->idKey]];

Hello can you help me?

tree with max 3 children for each node

Hello,
i have mysql table structured for tree where each node have maximum 3 nodes in each level.
Example node1 is in row=1 & column=1
node 1 has 3 childrens where row=2 & column=1,=2, =3
next row is row=3 and have 9 possibles of column from col=1 to col=9

How i can use your code to insert new node in his right position if i know the parent
Exmaple if i want insert new node for parent node1(row=1, col=1) the logic must be row=3 & col=1

in my db structure each node saved in 1 record with data: id, id_parent, row, column,id_reffer

id_parent is the parent id of direct sub level
id_reffer is the parent id first level

Can help me? Thanks

"getNodeById" returns non-existent nodes

\BlueM\Tree::getNodeById() returns non-existent nodes:

$data = [];
$sut = new BlueM\Tree($data);

// #1: returns a "\BlueM\Tree\Node" (incorrect)
var_dump($sut->getNodeById(0));

// #2: throws InvalidArgumentException (correct)
var_dump($sut->getNodeById(1));

Expected behavior: when an id does not exist, an \InvalidArgumentException should be thrown.


Details

There seems to be a problem with 0 (int), '0' (string) and false (bool):

// arrange
$data = [];
$sut = new BlueM\Tree($data);

$cases = [-1, 0, 1, '-1', '0', '1', PHP_INT_MIN, PHP_INT_MAX, true, false, null];
foreach ($cases as $case) {
    try {
        // act
        $result = $sut->getNodeById($case)->toArray();

        // assert
        assert(!is_array($result), 'fail: FIXME');

    } catch (InvalidArgumentException $e) {
        var_dump(['case' => $case, 'result' => 'pass']);

    } catch (Throwable $e) {
        var_dump(['case' => $case, 'result' => $e->getMessage()]);
    }
}

Result:

array (size=2)
  'case' => int -1
  'result' => string 'pass' (length=4)

array (size=2)
  'case' => int 0
  'result' => string 'fail: FIXME' (length=11)

array (size=2)
  'case' => int 1
  'result' => string 'pass' (length=4)

array (size=2)
  'case' => string '-1' (length=2)
  'result' => string 'pass' (length=4)

array (size=2)
  'case' => string '0' (length=1)
  'result' => string 'fail: FIXME' (length=11)

array (size=2)
  'case' => string '1' (length=1)
  'result' => string 'pass' (length=4)

array (size=2)
  'case' => int -9223372036854775808
  'result' => string 'pass' (length=4)

array (size=2)
  'case' => int 9223372036854775807
  'result' => string 'pass' (length=4)

array (size=2)
  'case' => boolean true
  'result' => string 'pass' (length=4)

array (size=2)
  'case' => boolean false
  'result' => string 'fail: FIXME' (length=11)

array (size=2)
  'case' => null
  'result' => string 'pass' (length=4)

Getting whole tree as JSON object?

Hi,

Sorry if I'm missing something - but I have an array of arrays, passed into the Tree constructor - ids and parent ids set correctly, not getting any errors.

But when I json_encode the result.. it's just a flat array as it was when I passed it? There's no hierarchy, no nesting of nodes?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.