PHPackages                             se7enxweb/exp-platform-ng-subtree-copy-with-layouts - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. se7enxweb/exp-platform-ng-subtree-copy-with-layouts

ActiveSymfony-bundle

se7enxweb/exp-platform-ng-subtree-copy-with-layouts
===================================================

Copies an Ibexa DXP content subtree and carries over Netgen Layouts resolver rules, section assignments and object state metadata to the newly created locations.

v1.0.0(1w ago)10GPL-2.0-or-laterPHPPHP &gt;=8.2

Since Mar 12Pushed 1w agoCompare

[ Source](https://github.com/se7enxweb/SevenxExpPlatformNGSubtreeCopyWithLayouts)[ Packagist](https://packagist.org/packages/se7enxweb/exp-platform-ng-subtree-copy-with-layouts)[ Docs](https://se7enx.com)[ Fund](https://account.venmo.com/u/se7enxweb)[ Fund](https://cash.app/$7xweb)[ RSS](/packages/se7enxweb-exp-platform-ng-subtree-copy-with-layouts/feed)WikiDiscussions main Synced today

READMEChangelog (1)Dependencies (9)Versions (2)Used By (0)

SevenxExpPlatformNGSubtreeCopyWithLayouts Bundle
================================================

[](#sevenxexpplatformngsubtreecopywithlayouts-bundle)

Copies an Ibexa content subtree and automatically:

- Duplicates all matching [Netgen Layouts](https://netgen.io/layouts) resolver rules for the newly created location IDs.
- Re-applies the **section assignment** of each source content item to its corresponding copy.
- Re-applies all **object state** values of each source content item to its corresponding copy.

Ibexa's built-in `LocationService::copySubtree()` creates new locations with new IDs but loses three pieces of metadata that are not part of content versions: the Netgen Layouts resolver rules, the section assignment, and the object state assignments. This bundle restores all three.

---

Files
-----

[](#files)

FilePurpose`SevenxExpPlatformNGSubtreeCopyWithLayoutsBundle.php`Bundle entry point — loads `Resources/config/services.yaml``Resources/config/services.yaml`Autowire / autoconfigure for the bundle namespace`Service/SubtreeLayoutRuleCopier.php`Core service: parallel tree traversal + Netgen Layouts rule duplication`Service/SubtreeSectionCopier.php`Service: re-applies section assignments to each copied content item`Service/SubtreeObjectStateCopier.php`Service: re-applies all object state values to each copied content item`Command/CopySubtreeWithLayoutsCommand.php`Console command `se7enx:nglayouts:copy-subtree-with-layouts`**Modified by bundle registration:** `config/bundles.php`

---

Namespace
---------

[](#namespace)

```
App\Bundle\SevenxExpPlatformNGSubtreeCopyWithLayouts\

```

The project's existing `composer.json` autoload entry `"App\\": "src/"` covers this namespace automatically — no additional PSR-4 entry is needed and none was added (adding a second overlapping entry triggers Symfony's `DebugClassLoader`to double-include the bundle class file, causing a fatal "Cannot redeclare class" error).

---

Installation
------------

[](#installation)

See [doc/INSTALL.md](doc/INSTALL.md) for full installation instructions.

The bundle is registered in `config/bundles.php`:

```
App\Bundle\SevenxExpPlatformNGSubtreeCopyWithLayouts\SevenxExpPlatformNGSubtreeCopyWithLayoutsBundle::class => ['all' => true],
```

No other configuration is required. All services are autowired.

---

Usage
-----

[](#usage)

```
# Full copy — subtree + sections + object states + Netgen Layouts rules
php bin/console se7enx:nglayouts:copy-subtree-with-layouts

# Preview what would happen — no content or rules are written
php bin/console se7enx:nglayouts:copy-subtree-with-layouts 385 42 --dry-run

# Copy content + sections + object states only; skip layout rules
php bin/console se7enx:nglayouts:copy-subtree-with-layouts 385 42 --skip-layout-rules

# Copy content + layout rules only; skip section and object state re-assignment
php bin/console se7enx:nglayouts:copy-subtree-with-layouts 385 42 --skip-sections --skip-object-states
```

### Arguments

[](#arguments)

ArgumentDescription`source-location-id`Location ID of the root of the subtree to copy`target-parent-location-id`Location ID of the parent that will receive the copied subtreeOptions
-------

[](#options)

OptionDescription`--dry-run`Print what would be done without writing anything to the repository`--skip-layout-rules`Do **not** duplicate Netgen Layouts resolver rules`--skip-sections`Do **not** re-apply section assignments`--skip-object-states`Do **not** re-apply object state values---

How It Works
------------

[](#how-it-works)

1. **Copy the Ibexa content subtree.**
    `LocationService::copySubtree(source, targetParent)` is called with the admin user (ID 14) as the current user reference, so the copy has full repository access. The new root `Location` is returned.
2. **Build an old → new location ID map.**
    Both the original and the copied tree are traversed in parallel (child by child, in order) via `LocationService::loadLocationChildren()`. The result is an array of the form `[oldLocationId => newLocationId]` covering every node in the subtree.
3. **Re-apply section assignments.**
    For each `[oldLocationId => newLocationId]` pair the section of the source content item (`SectionService::getSectionOfContent()`) is read and then assigned to the new content item (`SectionService::assignSection()`).
    Ibexa's built-in copy inherits the section of the target parent; this step restores the original per-item section granularity.
4. **Re-apply object state assignments.**
    For every `ObjectStateGroup` returned by `ObjectStateService::loadObjectStateGroups()`, the source content item's state is read via `ObjectStateService::getContentState()` and written to the new content item via `ObjectStateService::setContentState()`.
5. **Duplicate `ibexa_location` rules for every location.**
    For each `oldLocationId` in the map, `nglayouts_rule_target` is queried directly via Doctrine DBAL (the `LayoutResolverService` API exposes no "find rules by target value" lookup). Every published, enabled rule whose target type is `ibexa_location` and whose value equals the old location ID is duplicated:

    - A new rule draft is created via `LayoutResolverService::createRule()`.
    - A target is added via `LayoutResolverService::addTarget()`.
    - The rule is published via `LayoutResolverService::publishRule()`.
6. **Duplicate `ibexa_subtree` rules for the copy root.**
    `ibexa_subtree` rules are subtree-wide, so they are only meaningful for the topmost copied location. The service copies these for the source root into a matching rule targeting the new root.
7. **Priority offset.**
    New rules receive `originalPriority − 1`. This ensures the original rules always take precedence over the copies, preserving existing page behaviour.

---

Supported Target Types
----------------------

[](#supported-target-types)

Target typeCopied for`ibexa_location`Every location in the subtree`ibexa_subtree`The copy root only`path_info_prefix`**Not copied** — path-based rules depend on URL aliases that Ibexa manages separately---

Dependencies
------------

[](#dependencies)

All injected via autowiring:

ServiceUsed for`Ibexa\Contracts\Core\Repository\LocationService``copySubtree()`, `loadLocation()`, `loadLocationChildren()``Ibexa\Contracts\Core\Repository\PermissionResolver`Setting admin user as current reference`Ibexa\Contracts\Core\Repository\UserService`Loading admin user by ID`Ibexa\Contracts\Core\Repository\SectionService``getSectionOfContent()`, `assignSection()` on each copied item`Ibexa\Contracts\Core\Repository\ObjectStateService``loadObjectStateGroups()`, `getContentState()`, `setContentState()` on each copied item`Netgen\Layouts\API\Service\LayoutResolverService``newRuleCreateStruct()`, `createRule()`, `newTargetCreateStruct()`, `addTarget()`, `publishRule()`, `loadRuleGroup()``Doctrine\DBAL\Connection`Direct query of `nglayouts_rule_target` by target value---

Database Schema Reference
-------------------------

[](#database-schema-reference)

The following nglayouts tables are read (never written to directly):

```
-- status = 1 means PUBLISHED in all nglayouts tables
nglayouts_rule        (id, status, uuid, rule_group_id, layout_uuid, description)
nglayouts_rule_data   (rule_id, enabled, priority)
nglayouts_rule_target (id, status, uuid, rule_id, type, value)
```

The root rule group UUID is fixed in the nglayouts schema:

```
00000000-0000-0000-0000-000000000000

```

All new rules are created under this group, matching the behaviour of rules created via the Netgen Layouts admin UI.

---

License &amp; Copyright
-----------------------

[](#license--copyright)

Copyright © 1998 - 2026, 7x. All rights reserved.

SevenxExpPlatformNGSubtreeCopyWithLayouts is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version.

SevenxExpPlatformNGSubtreeCopyWithLayouts is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with SevenxExpPlatformNGSubtreeCopyWithLayouts in [LICENSE](LICENSE.md). If not, see .

See [COPYRIGHT.md](COPYRIGHT.md) for full copyright and license assignment details.

###  Health Score

40

—

FairBetter than 88% of packages

Maintenance98

Actively maintained with recent releases

Popularity2

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity45

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

9d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/d2a5049c5b1e7a22c301a2472d09281be35f717da316873861c1a8ae785ada7a?d=identicon)[7x](/maintainers/7x)

---

Top Contributors

[![se7enxweb](https://avatars.githubusercontent.com/u/51429274?v=4)](https://github.com/se7enxweb "se7enxweb (5 commits)")

---

Tags

symfonysectionSymfony Bundleibexa-dxpnetgenibexanetgen-layoutssubtree-copylayout-resolverobject-statese7enxweb

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Type Coverage Yes

### Embed Badge

![Health badge](/badges/se7enxweb-exp-platform-ng-subtree-copy-with-layouts/health.svg)

```
[![Health](https://phpackages.com/badges/se7enxweb-exp-platform-ng-subtree-copy-with-layouts/health.svg)](https://phpackages.com/packages/se7enxweb-exp-platform-ng-subtree-copy-with-layouts)
```

###  Alternatives

[incenteev/hashed-asset-bundle

Apply an asset version based on a hash of the asset for symfony/asset

25521.0k1](/packages/incenteev-hashed-asset-bundle)[tito10047/altcha-bundle

A simple package to help integrate Altcha on Symfony.

158.2k1](/packages/tito10047-altcha-bundle)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
