Download the PHP package ericgansa/ghost-trees-bundle without Composer

On this page you can find all versions of the php package ericgansa/ghost-trees-bundle. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package ghost-trees-bundle

Ghost Trees Bundle

Tests Latest Version PHP Version

Imaginez un Chef étoilé qui publie une recette

Trois cuisiniers s'inscrivent pour la cuisiner chez eux. Marie ne change rien — elle suit le Chef à la lettre. Thomas adapte juste le temps de cuisson à son four. Sophie réinvente la moitié de la recette. Le Chef corrige une faute de frappe : Marie en bénéficie automatiquement, Thomas aussi sur ce qu'il n'a pas modifié, Sophie reçoit ce qu'elle n'a pas touché. Personne n'a cliqué sur "synchroniser". Personne n'a invalidé un cache. Les valeurs apparaissent simplement là où elles sont attendues.

Imaginez un manager qui prépare un déplacement pour son équipe

Cinq agents y sont rattachés. Chacun reçoit une copie fantôme du programme. Le manager modifie l'horaire du train du retour : tous les agents le voient. Un agent change d'hôtel pour des raisons personnelles : seule sa copie diverge, les autres restent alignées sur le programme initial. Plus tard, le manager annule la mission. Au lieu de tout perdre, chaque agent voit sa copie incarnée en demande indépendante, qu'il peut garder ou clôturer.

Imaginez une plateforme SaaS multi-tenants

Une configuration globale définit les valeurs par défaut : couleurs de marque, quotas, feature flags. Chaque tenant hérite, et peut surcharger. Chaque utilisateur dans le tenant peut surcharger encore au-dessus. Le SaaS active une nouvelle fonctionnalité globalement : elle apparaît chez tous les tenants qui n'ont pas surchargé ce flag, et dans toutes les sessions utilisateurs concernées. Aucun batch d'invalidation. Aucun job de propagation. Juste de la résolution paresseuse à la lecture.

Le pattern derrière ces trois scènes

Dans chaque cas, il y a un original et des copies vivantes qui héritent par défaut. La différence d'avec un clone : la copie n'est jamais figée — elle suit l'original tant qu'elle ne le contredit pas. La différence d'avec une référence : la copie peut diverger localement, sur le champ exact qu'elle veut, sans casser le lien.

C'est le pattern des arbres fantômes, et c'est ce que ce bundle apporte à Doctrine.

Le système repose sur un modèle d’arbre fantôme (Ghost Tree Pattern), dans lequel les entités métier sont structurées en hiérarchie parent/enfant. Chaque entité enfant hérite dynamiquement des attributs de son parent tout en pouvant surcharger individuellement certains champs. Cette approche permet de représenter des variations contextuelles d’un même objet métier sans duplication de données, en garantissant une cohérence structurelle et une flexibilité d’adaptation.


Pitch en 30 secondes

Effacer "Marseille" → la lecture redevient "Lyon". Aucune copie. Aucun cache.


Fonctionnalités

Résolution dynamique attribut par attribut

Chaque getter d'un fantôme retourne sa valeur locale si elle existe, sinon la valeur du parent par traversée. Granularité au champ près : un fantôme peut hériter du titre et personnaliser la durée, sans logique applicative.

Matérialisation et dématérialisation réversibles

Donner une valeur locale matérialise (l'attribut diverge). Remettre null dématérialise (l'attribut revient à hériter). Pas de bouton "synchroniser" à coder, pas d'historique à gérer — la sémantique est portée par la valeur elle-même.

Incarnation (promotion en racine autonome)

Un fantôme suffisamment divergent peut être détaché de son parent : toutes ses valeurs résolues sont matérialisées localement, le lien parent est coupé. Utile pour les workflows où une copie devient une entité de premier rang (publication, archivage, autonomie).

Propagation structurelle des collections

Quand un élément est ajouté à une collection de la racine, le bundle crée automatiquement les fantômes correspondants dans chaque enfant. Côté Doctrine, c'est un EventSubscriber câblé sur onFlush. Côté code applicatif, rien à écrire.

Possession exclusive

Un élément créé directement par un fantôme (sans parent) lui appartient en propre. La racine ne peut ni le voir en écriture, ni le supprimer. Sépare proprement ce que j'hérite de ce que j'ajoute.

Validation conditionnelle

L'attribut #[RequiredOnRoot] rend un champ obligatoire uniquement sur les racines. Sur les fantômes, la contrainte se tait — le champ peut rester null puisqu'il sera résolu depuis le parent. Plus de Assert\When qui pollue chaque entité.

Stratégie de suppression configurable

Lorsqu'une racine est supprimée, deux comportements au choix :

Câblé via le subscriber, contrôlé en YAML.

Outillage d'introspection

Trois services, exposés en interfaces, accessibles partout par autowiring :

Et deux commandes CLI prêtes à l'emploi : debug:ghosts et ghosts:incarnate.

Cache de réflexion

GhostMetadata met en cache les ReflectionProperty des entités fantomisables après le premier accès. Les opérations massives (debug, incarnation par lot) ne re-introspectent pas à chaque appel.


Installation

Activez le bundle dans config/bundles.php (Flex le fait pour vous) :


Configuration

Option Type Défaut Effet
max_depth int ≥ 1 1 Profondeur maximale de la chaîne fantôme.
on_root_delete cascade | incarnate cascade Comportement à la suppression d'une racine.
auto_propagate_collections bool true Active la propagation structurelle automatique côté collections.

Rendre une entité fantomisable

Sans Doctrine (DTO, fixtures, tests) : aucune redéclaration de $parent nécessaire. Le trait porte tout.


API de l'entité (méthodes du trait)

Méthode Description
isGhost() Vrai si l'entité a un parent
getParent() / setParent() Accès au lien parent
incarnate() Matérialise toutes les valeurs héritées localement, coupe le lien parent
reset() Efface toutes les surcharges locales (retour à la transparence)
createGhostOf($original) Fabrique un fantôme vierge rattaché à $original (statique)
resolve($local, $getter) Résolution d'un attribut dans les getters (protégé)

Exemples


Services injectables

Le bundle expose trois services par autowiring. Ils permettent les opérations qui ne peuvent pas vivre dans une entité (validation transversale, dispatch d'événements, accès à la base).

GhostResolverInterface

Résolution brute et validation structurelle (profondeur, cycle).

GhostInspectorInterface

Introspection : d'où vient chaque valeur, l'entité a-t-elle divergé.

Idéal pour des badges UI "modifié / hérité / non défini" et le débogage en CLI.

GhostIncarnatorInterface

Incarnation transactionnelle, avec dispatch d'événement.

Les versions $ghost->incarnate() (méthode du trait) et $incarnator->incarnate($ghost) (service) coexistent : la première est autonome et silencieuse, la seconde émet l'événement applicatif. À choisir selon que ton domaine doit réagir à l'incarnation ou non.


Événements

Le bundle dispatche des événements aux moments clés du cycle de vie. Tout listener Symfony classique peut s'y abonner.

Événement Quand il est émis Charge utile
GhostAffiliatedEvent Une entité vient d'être rattachée à un parent entity, parent
GhostIncarnatedEvent Une entité vient d'être incarnée (par le service) entity, previousParent

Exemple : audit des incarnations

Exemple : notification à l'auteur de la racine


Doctrine subscriber

Le bundle enregistre automatiquement GhostPropagationSubscriber, qui implémente deux comportements transversaux à toutes les entités fantomisables.

Comportement 1 — Propagation structurelle (onFlush)

Lors de l'ajout d'un élément à une collection portée par une racine, le subscriber crée automatiquement les fantômes correspondants chez les enfants.

Désactivable via la config auto_propagate_collections: false si tu veux gérer la propagation toi-même.

Comportement 2 — Stratégie de suppression (preRemove)

Lorsqu'une racine est sur le point d'être supprimée, le subscriber consulte la config on_root_delete :

Limites


🔐 Sécurité

Protection contre les cycles

Niveau Mécanisme Garantie
Direct (A→A) setParent() dans le trait Exception immédiate
Indirect (A→B→A) GhostResolver::assertValidParent() Exception avant persistence
Données corrompues (SQL direct) SplObjectStorage dans GhostIncarnator GhostCycleException
Debug sur données corrompues SplObjectStorage dans GhostInspector Retourne source='cycle_detected'

Invariants garantis

  1. Profondeur : aucune chaîne fantôme ne dépasse max_depth.
  2. Pas de cycle : une entité ne peut pas être son propre ancêtre.
  3. Transparence de lecture : un fantôme non matérialisé lit depuis le parent.
  4. Isolation d'écriture : modifier un fantôme n'affecte jamais le parent.
  5. Réversibilité : reset() restaure la lecture transparente.

Gestion Doctrine sécurisée


🧪 Qualité

Analyse statique

Tests

Formatage

Mutation testing (optionnel)

QA complète (avant PR)

Hooks pre-commit (GrumPHP)

Bloque le commit si : test cassé · erreur PHPStan · code non formaté · CVE connue.


Attributs PHP

Attribut Rôle
#[GhostField] Marque une propriété pour la résolution dynamique (introspection)
#[RequiredOnRoot] Validation : champ obligatoire sur les racines, silencieux sur les fantômes

#[Ghostable] et #[GhostableField] sont des alias dépréciés conservés pour la compatibilité. Ils seront supprimés en v1.0.


Vocabulaire

Terme Sens
Racine Entité sans parent. Source des valeurs originales.
Fantôme Entité avec un parent. Hérite dynamiquement les valeurs non matérialisées.
Matérialisation Écriture d'une valeur locale sur un champ fantôme.
Dématérialisation Effacement d'une valeur locale (→ reset()). La résolution dynamique reprend.
Incarnation Promotion d'un fantôme en racine : matérialisation + coupure du lien parent.
Possession exclusive Un élément créé directement par un fantôme lui appartient et n'est pas visible en écriture côté racine.
Propagation structurelle Création automatique de fantômes dans les enfants quand un élément est ajouté à une collection de la racine.

Outillage CLI


Limites connues (v0.x)


Documentation

Licence

MIT.


All versions of ghost-trees-bundle with dependencies

PHP Build Version
Package Version
Requires php Version >=8.2
doctrine/orm Version ^2.17 || ^3.0
symfony/config Version ^6.4.29 || ^7.3.6
symfony/console Version ^6.4.29 || ^7.3.6
symfony/dependency-injection Version ^6.4.29 || ^7.3.6
symfony/event-dispatcher-contracts Version ^3.0
symfony/http-kernel Version ^6.4.29 || ^7.3.6
symfony/validator Version ^6.4.29 || ^7.3.6
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package ericgansa/ghost-trees-bundle contains the following files

Loading the files please wait ...