This originally came from a discussion [years ago] on this issue #252846: Add XML Sitemap to Core, the original discussion on that issue no longer seems to be relevant but the ideas it spawned here are. Those relevant ideas are:

  • An abstract mechanism that can handle both hierarchical (such as the menu and the book mechanisms) and non hierarchical relations between nodes (such as taxonomy and several contributed modules), and offer this knowledge to contributed modules through an API.
  • This new mechanism could handle the relationships that the menu and book Core Modules require, and provide structural data to modules like XML sitemap, Sitemap, etc.

It would be the goal of something like a "structure.module" or "relationships.module" to manage and maintain the different kinds of relations between Entities (mainly Nodes). If the relations are hierarchical, they could be offered to something like "book.module" that handles displaying the structure to users.

This new mechanism would not be a subset of Menu, Taxonomy, Books or another Core Module since this API and the relations it establishes would have to be more low-level and not specific to one modules data structure or workflow, as well as providing the ability to *all* content a Drupal site consists of so that moules like Menu, Taxonomy and Books could be based on this API.

The Problem

Drupal Core does not know much about the relations of content in a Drupal site; some "connections" are created through taxonomy, others through the menu and book modules. Also, there is a plethora of contributed modules trying to add this information about parent-child-relations, etc.. All those modules try to solve similar problems and to generate similar data, thus multiplying the effort to maintain this knowledge about a site's structure. Additionally, most of those approaches do not make good use of data already available in other modules. When building a site, this can lead to unnecessary complex site structures with different navigation themes, different hierarchies, performance issues, etc. We all know these problems. That's the reason, why a solution in Core is needed.

Similar Approaches

Many contributed modules try to add knowlede about a Site to Drupal; some examples:

There are many more modules with similar requirements.

These modules have completely different goals, and different "targets":

  • "Simple Sitemap" and "XML Sitemap" are targeted to machines like search engines; they generated internal representations of a website's structure, but don't offer this to the site's human users
  • "Site map" and "Site menu" are targeted to end users; they build a visual representation about a site and provide a page with links, that a user can click
  • The core "Book" and "Menu" modules provide tools to edit relations between nodes, and/or to represent them in form of a table of contents page, or a menu.
  • Modules like "Node Hierarchy" or "Node Relativity" mostly help creating relations between nodes but don't display them to end users; also, they don't provide their data to other tools like "XML sitemap"
  • Modules like "Node Relativity" allows to create parent-child relationships, similar to the book mechanism, but don't integrate well to other structural tools.

Why does this need to be in Core and not in a contributed module?

IMHO it's as simple as this: Drupal is a framework offering an infrastructure to build intelligent websites. Knowledge about structural relations between nodes is such an infrastructure.

  • Harvesting a site for node's relations creates severe performance issues, especially on large sites; every contributed module has to find a solution on it's own. The developers of the "XML sitemap" module solved a lot of these issues during the last months, otheres like "Site Map" or "Site Menu" didn't; knowlegde in Core about a site's structure would provide the data to contributed modules, making a Drupal site perform better and reduce overhead;
  • Drupal Core already has mechanisms to manage hierarchical relations between nodes (book, and menu modules); but it can't handle non-hierarchical relations, and both modules should be integrated on a more abstract basis.
  • Contributed modules could concentrate fully on their specific goals (e.g. providing a XML sitemap to search engines, or provide a human-readable sitemap to users, or provide navigational menues, etc.)

I'm searching for quite some time for solutions to the described problems; so far, I only discovered approaches targeting parts of it. This feature request is intended to

  • either start a discussion about getting structural knowledge about a site's content into core,
  • or to point to already existing discussions about this topic if I missed those.

[Thanks & Greetings, -asb]

Comments

jscheel’s picture

I wonder if the push for getting RDF into D7 would help with this. Honestly, I don't even know if that is going to happen anymore, I've been out of the loop for a while...

Well, subscribing anyways.

mdupont’s picture

Version: 7.x-dev » 8.x-dev

I guess the most promising work in this direction currently is Relation module.

Version: 8.0.x-dev » 8.1.x-dev

Drupal 8.0.6 was released on April 6 and is the final bugfix release for the Drupal 8.0.x series. Drupal 8.0.x will not receive any further development aside from security fixes. Drupal 8.1.0-rc1 is now available and sites should prepare to update to 8.1.0.

Bug reports should be targeted against the 8.1.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.9 was released on September 7 and is the final bugfix release for the Drupal 8.1.x series. Drupal 8.1.x will not receive any further development aside from security fixes. Drupal 8.2.0-rc1 is now available and sites should prepare to upgrade to 8.2.0.

Bug reports should be targeted against the 8.2.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.2.x-dev » 8.3.x-dev

Drupal 8.2.6 was released on February 1, 2017 and is the final full bugfix release for the Drupal 8.2.x series. Drupal 8.2.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.3.0 on April 5, 2017. (Drupal 8.3.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.3.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

colan’s picture

Title: Abstraction layer plus API for structural knowledge about a site's content in Core (book, menu, relativity and sitemap modules) » Provide an entity hierarchy API
Project: Drupal core » Drupal core ideas
Version: 8.3.x-dev »
Component: other » Idea
Category: Feature request » Plan

I've reviving this based on the discussion we've been having in #1261130: [PP-1] Rewrite book module to use a standard, reusable API for creating hierarchies.

It makes perfect sense for use by Menu, Taxonomy, and Book. The Book module could be kicked into Contrib or not (separate issue), but either way, it would use the API.

As far as storage goes, we would need to store a parent ID (at least).

This would help a certain class of issues that have been popping up:

There's an Entity Reference Hierarchy module that may serve as a useful model. It already has a #2862096: Replace Book module issue.

aaronmchale’s picture

Updated the original idea text to be a little more generic and more relevant to the state of Drupal today, as well as fixed some formatting.

@colan also added the issues you linked as related issues

To me it seems like an obvious implementation of this API could centre around the Entity Reference Field Types, which would probably be a good basis to work from since it already has the ability to create the relationships we are talking about. Additionally since they are fields it means they are very easily useable by other parts of the system, such as when creating Views.

So running with that train of thought, here are some questions we should consider answering and some of my thoughts:

  1. Do the Entity Reference Field Types already provide enough information and API to simply just use them as this proposal and refactor the existing core module to just use Entity Reference Fields?
  2. In addition to the above would the implmention also need an abstraction layer in the Fieldable Entity API that provides methods like getChildren(), getSiblings(), getParents(), etc, which work using Entity Reference Fields to provide their information?

Thinking on that a potential issue I see with 2 (question 2 above) is that it would be hard for a module like Books to know which relationships to use when using this abstraction layer. For example if a node has a Entity Reference Field relating to a Book but also relating to a Taxonomy and another relating it to a parent item in a menu, which could cause some confusion. So we'd either need some kind of identifier when returning the Entities from the API Methods indicating what field the relationship came from. That could be in the form of a "Entity Reference Results Object" or a multi-dimension array.

For example getParents() returns the above mentioned object which has methods such as:

  • getRelations() which just returns an array of all related entities
  • getReferenceFields() which returns an array of Entity Reference Fields
  • getRelationsFromField($field) which accepts a specific field object and returns an array of entities

Personally I'm in favour of the object approach since it's better for those like myself using IDEs such as PhpStorm.

Another potential issue is that right now Entity Reference Fields don't have the concept of defining Parent, Child and Sibling relationships, so we'd need a way for this identifier to be implemented. Most likely an additional configuration property for each Entity Reference Field which allows the admin creating the Field to define if Entities added to this field are parents, children or siblings. You wouldn't want this to show for users when they are adding the individual Entity References, as that could just be confusing, and in the majority of cases the way each Field is used implies if Entities added are parents, children or siblings.

Implementing this idea with a small API extension to the Fieldale Entity API being just based on Entity Reference Fields I think would be both the most minimal amount of work but also provide the highest reward, since it would then be easy to maintain and provide a very solid foundation for other Core and Contrib modules to hook into with minimal effort.

Assuming we agree on all of this question then becomes, what does the UI look like and how does the user interact with this when it comes to modules actually implementing it such as Book, Menu and Taxonomy?

At the moment that is what I'm unsure of, because while this is a great solution from an API point of view it has the potential to be difficult for inexperienced users to work with. Right now users just enable the Books module, they can then start creating Books, they don't have to worry about adding Entity Reference Fields and making sure the Book module knows about them. So I think it's important for us to find a way to make this work which doesn't result in users seeing any more complexity.

Thanks
Aaron

giorgio79’s picture

gabesullice’s picture

@AaronMcHale,

Thinking about a potential API and looking at the (high-level) approach taken by tree for D7. I think there needs to be two things:

  1. "Hierarchies" as entities
  2. A new field type

Defining hierarchies as entities means an entity will be able to belong to many hierarchies, not just one. It also provides the ability to load and moderate a hierarchy.

The new field type would have two entity reference properties, a child property that would be a reference to another entity and a member_of property that would be a reference to the hierarchy entity.

To make an entity type "treeable" one would only need a "hierarchy" field to store items of this new field type. A hierarchy_parent field could be computed (like term parent).

To get parents/children for a distinct hierarchy, one could just filter the field items by the member_of property (the filter callback could be provided by the hierarchy entity).

// load any hierarchy entities referenced by the new field type
$hierarchies = $entity->hierarchy->getHierarchies();
// get the children for a particular hierarchy
$children = $entity->hierarchy->filter($hierarchy[0]->getFieldItemFilter())->getReferencedEntities();

This approach also makes it fast to load all entities belonging to a hierarchy because the entity query system already allows filtering on properties of a field:

$hierarchy = Hierarchy::load($id);
$entities_in_hierarchy = \Drupal::entityQuery($hierarchy->getMemberEntityType()->id())->condition('hierarchy.member_of', $hierarchy->id());

This could be implemented using a new hierarchy entity type. Bundles of the hierarchy type would be tied to a target entity type (i.e. you could create a new hierarchy type that can contain terms, or a new hierarchy type that can contain nodes, or link items). These hierarchy types could be fieldable (to contain a menu title, for example).

In whatever module adds this, one would then implement hook_base_field_info_alter to add the hierarchy field to any entity type which is targeted by a hierarchy bundle.


What I particularly like about the approach above is that (in theory) this can all be done without changing much of the Field API. One doesn't need to add any new core interfaces to find out if an entity can be in a hierarchy for example. Instead, you can just do:

$treeable = $entity instanceof FieldableEntityInterface && $entity->hasField('hierarchy');

All of the specific methods for managing a hierarchy would be contained to the new hierarchy entity type or the new field type (which could be done in core or contrib!).

In terms of a UI, the draggable things like taxonomy has would be managed from each particular hierarchy entity edit page.

heddn’s picture

Re #9: term parent calculation has gone away in 8.6 of Drupal. It now uses a normal entity reference field. The child or the parent can be automatically calculated (depending on the direction of the relationship), so storing both is probably not needed.

Can you expound on the intermediary hierarchy entity and what problems it solves that entity reference fields do not?

colan’s picture

Good question. I typically get by with a single Entity Reference field for pointing to a parent entity.

gabesullice’s picture

@heddn, as far as I'm aware, it's still a computed field in 8.6, no? Perhaps we're saying the same thing differently?

I wouldn't label the hierarchy entity as "intermediary", it's more like a grouping mechanism.

Let's say I have user entities and I want to represent family trees and org-charts in the same application (bizarre, but let's roll with it).

A user might be the biological parent of some other user and simultaneously also be another user's boss. The family and the org chart are distinct hierarchies.

How do I differentiate between entity reference items that target child entities for the family tree and child entities for some org chart? If all the child entities are in a vanilla entity reference field, there would be no way to do so. Getting the children of that user would turn up both the user's biological children and the user's direct reports.

To solve that, the "hierarchy entity" would be the thing that represented say, the "Smith Family Tree" or the "Widget Corp Org Chart". The new field type would pair an entity reference to a child entity with a reference to the "hierarchy" to differentiate the nature of the relationship.

With a pure entity reference field, you'd need to have distinct fields for every possible tree to which an entity could belong. That's a bit how terms work now, they can just belong to one hierarchy, based on the vocabulary config entity. Thus, having a distinct field for every hierarchy type would quickly become unscalable. It would also prevent content authors from creating new hierarchies (in the same way that they can't create vocabularies without the 'administer taxonomy' permission).

The new field type I'm proposing would be a composition of two EntityReferenceItems, one would reference a child entity and one would reference the hierarchy to which the relationship "belongs."

heddn’s picture

Ah, that makes more sense now. Thanks for the detailed explanation. Does the hierarchy API need to support more than a single hierarchy without multiple fields? I guess that deserves an answer.

BTW, here's the CR where term parents was converted in 8.6: https://www.drupal.org/node/2936675

gabesullice’s picture

BTW, here's the CR where term parents was converted in 8.6

Derp. I really don't know what I was thinking of (just my imagination I guess).

You're absolutely right though! So, thank you for the explanation :)

gabesullice’s picture

Does the hierarchy API need to support more than a single hierarchy without multiple fields?

I believe it would be a really frustrating constraint if it didn't. To take another family tree example, it would be impossible to create a kind of genealogy site.

For example, if person A is in the Foo Family tree and marries person B in Bar Family tree, the only way to reconcile that with would be a new field for the Foo family and a new field for the Bar family. You'd quickly end up with hundreds or thousands of fields. (or you'd have to put them all in one mega-tree that would not be at all performant).

Does the hierarchy "need" to support that? It certainly couldn't, but I believe it would be a real lost-opportunity if it didn't.

Edit: Another more familiar example: adding a node to many books.

giorgio79’s picture

giorgio79’s picture

Issue summary: View changes
aaronmchale’s picture

I don't think we should go as far as to define a new Entity Type for hierarchies, as for most practical cases you would have no use for such an Entity, for example Books has a hierarchy but it just uses the top level node as the entity which the hierarchy sits under, Taxonomy, Menu and others already define their own Entity Types.

So adding a new Entity that the system has to keep track of might be a bit overkill and might limit the potential use case of this API.

We have to look at fundamentally what we are trying to accomplish here and to it in the most flexible way. As such it seems like the easiest approach is just to extend the scope of the existing Entity Reference Field Type to include the concept of parent and child relationships like I suggested in #7. Since fields can already have multiple values it wouldn't be a problem to have an Entity Reference Field reference multiple other Entities to make the current Entity part of multiple hierarchies.

In summary we shouldn't be thinking about defining what the hierarchy is, we should just focus on extending Core APIs to provide the building blocks for the concept of "hierarchical relationships between Entities" to allow other modules like Books, Menus, Taxonomy, etc to define what the Hierarchy is. Doing this is the most extensible and least restrictive approach.

neograph734’s picture

It might also be an idea to look into a model similar to the relation module for Drupal 7. That module uses 'entity references' that are fieldable entities themselves. It would allow a menu or taxonomy term to be a (many-to-one) reference to childs, whilst also providing field for storing metadata such as the menu link text or the taxonomy term name.

murz’s picture

Very light and easy example of Entity Hierarchy implementation is Bricks module for 8.x, and it's predecessor - Tree module for 7.x. So if Drupal will provide API for building hierarchy based on Entity Reference - this will already large step.

Next step is to provide more effective storage for large hierarchy trees and queries on this tree, because current "Flat table" storage (like in Bricks) is good only when we always operate with all tree, not with part of it.

For large trees good implementation is Entity Reference Hierarchy module, that have better storage based on previousnext/nested-set library.

nod_’s picture

dat deaf drupaler’s picture

Been experimenting with closing gaps between core Content Types + Storage Entities module + Entity Reference Hierarchy module, and proposed 'Junction of content type and entity storage type' issue.. would something like this be a possibility to include in part of this development track?

Concept #1: Content type - works well!

    Parent: content type
        |- Children: content type

Concept #2: Storage type - works well!

    Parent: storage type
        |- Children: storage type

Concept #3: Parent content type + child storage type - works however children does not show up when viewing parent content's children page (node/%/children)..?

    Parent: content type
        |- Children: storage type

Was wondering if it would be possible to close the gap between both entity bundles?

Storage Entities is quite powerful which offers the most appropriate (lightweight) content bundling alternative to paragraphs in regard to content modeling designs.

Thank you for your consideration.

quietone’s picture

Project: Drupal core ideas » Drupal core
Version: » 11.x-dev
Component: Idea » entity system
Category: Plan » Feature request

The Ideas project is being deprecated. This issue is moved to the Drupal project. Check that the selected component is correct. Also, add the relevant tags, especially any 'needs manager review' tags.

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.