Skip to content

Commit

Permalink
Merge branch '9.0' into feature/4726-extract-workspace-metadata-and-u…
Browse files Browse the repository at this point in the history
…ser-assignment-to-neos
  • Loading branch information
bwaidelich committed Oct 7, 2024
2 parents e64ff93 + 2a18885 commit 88e344d
Show file tree
Hide file tree
Showing 62 changed files with 3,843 additions and 984 deletions.
1 change: 1 addition & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ jobs:
touch ${{ github.workspace }}/Data/DebugDatabaseDumps/keep
./flow package:list --loading-order
FLOW_CONTEXT=Testing/Behat ./flow doctrine:migrate --quiet
cd Packages/Neos
# composer test:behavioral
Expand Down
9 changes: 6 additions & 3 deletions Neos.ContentRepository.Export/src/ExportService.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@
use League\Flysystem\Filesystem;
use Neos\ContentRepository\Core\Factory\ContentRepositoryServiceInterface;
use Neos\ContentRepository\Core\Projection\Workspace\WorkspaceFinder;
use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryId;
use Neos\ContentRepository\Export\Processors\AssetExportProcessor;
use Neos\ContentRepository\Export\Processors\EventExportProcessor;
use Neos\EventStore\EventStoreInterface;
use Neos\Media\Domain\Repository\AssetRepository;
use Neos\Neos\AssetUsage\Projection\AssetUsageFinder;
use Neos\Neos\AssetUsage\AssetUsageService;

/**
* @internal
Expand All @@ -19,10 +20,11 @@ class ExportService implements ContentRepositoryServiceInterface
{

public function __construct(
private readonly ContentRepositoryId $contentRepositoryId,
private readonly Filesystem $filesystem,
private readonly WorkspaceFinder $workspaceFinder,
private readonly AssetRepository $assetRepository,
private readonly AssetUsageFinder $assetUsageFinder,
private readonly AssetUsageService $assetUsageService,
private readonly EventStoreInterface $eventStore,
) {
}
Expand All @@ -37,10 +39,11 @@ public function runAllProcessors(\Closure $outputLineFn, bool $verbose = false):
$this->eventStore
),
'Exporting assets' => new AssetExportProcessor(
$this->contentRepositoryId,
$this->filesystem,
$this->assetRepository,
$this->workspaceFinder,
$this->assetUsageFinder
$this->assetUsageService
)
];

Expand Down
7 changes: 4 additions & 3 deletions Neos.ContentRepository.Export/src/ExportServiceFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
use Neos\ContentRepository\Core\Factory\ContentRepositoryServiceFactoryInterface;
use Neos\ContentRepository\Core\Projection\Workspace\WorkspaceFinder;
use Neos\Media\Domain\Repository\AssetRepository;
use Neos\Neos\AssetUsage\Projection\AssetUsageFinder;
use Neos\Neos\AssetUsage\AssetUsageService;

/**
* @internal
Expand All @@ -21,17 +21,18 @@ public function __construct(
private readonly Filesystem $filesystem,
private readonly WorkspaceFinder $workspaceFinder,
private readonly AssetRepository $assetRepository,
private readonly AssetUsageFinder $assetUsageFinder,
private readonly AssetUsageService $assetUsageService,
) {
}

public function build(ContentRepositoryServiceFactoryDependencies $serviceFactoryDependencies): ExportService
{
return new ExportService(
$serviceFactoryDependencies->contentRepositoryId,
$this->filesystem,
$this->workspaceFinder,
$this->assetRepository,
$this->assetUsageFinder,
$this->assetUsageService,
$serviceFactoryDependencies->eventStore,
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use League\Flysystem\Filesystem;
use Neos\ContentRepository\Core\Projection\Workspace\WorkspaceFinder;
use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryId;
use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName;
use Neos\ContentRepository\Export\Asset\ValueObject\SerializedAsset;
use Neos\ContentRepository\Export\Asset\ValueObject\SerializedImageVariant;
Expand All @@ -15,8 +16,8 @@
use Neos\Media\Domain\Model\AssetVariantInterface;
use Neos\Media\Domain\Model\ImageVariant;
use Neos\Media\Domain\Repository\AssetRepository;
use Neos\Neos\AssetUsage\AssetUsageService;
use Neos\Neos\AssetUsage\Dto\AssetUsageFilter;
use Neos\Neos\AssetUsage\Projection\AssetUsageFinder;

/**
* Processor that exports all assets and resources used in the Neos live workspace to the file system
Expand All @@ -29,10 +30,11 @@ final class AssetExportProcessor implements ProcessorInterface
private array $callbacks = [];

public function __construct(
private readonly ContentRepositoryId $contentRepositoryId,
private readonly Filesystem $files,
private readonly AssetRepository $assetRepository,
private readonly WorkspaceFinder $workspaceFinder,
private readonly AssetUsageFinder $assetUsageFinder,
private readonly AssetUsageService $assetUsageService,
) {}

public function onMessage(\Closure $callback): void
Expand All @@ -47,13 +49,13 @@ public function run(): ProcessorResult
if ($liveWorkspace === null) {
return ProcessorResult::error('Failed to find live workspace');
}
$assetFilter = AssetUsageFilter::create()->withContentStream($liveWorkspace->currentContentStreamId)->groupByAsset();
$assetFilter = AssetUsageFilter::create()->withWorkspaceName($liveWorkspace->workspaceName)->groupByAsset();

$numberOfExportedAssets = 0;
$numberOfExportedImageVariants = 0;
$numberOfErrors = 0;

foreach ($this->assetUsageFinder->findByFilter($assetFilter) as $assetUsage) {
foreach ($this->assetUsageService->findByFilter($this->contentRepositoryId, $assetFilter) as $assetUsage) {
/** @var Asset|null $asset */
$asset = $this->assetRepository->findByIdentifier($assetUsage->assetId);
if ($asset === null) {
Expand Down
2 changes: 1 addition & 1 deletion Neos.Media.Browser/Classes/Controller/UsageController.php
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ public function relatedNodesAction(AssetInterface $asset)

$contentRepository = $this->contentRepositoryRegistry->get($usage->getContentRepositoryId());

$workspace = $contentRepository->getWorkspaceFinder()->findOneByCurrentContentStreamId($usage->getContentStreamId());
$workspace = $contentRepository->getWorkspaceFinder()->findOneByName($usage->getWorkspaceName());

// FIXME: AssetUsageReference->workspaceName ?
$nodeAggregate = $contentRepository->getContentGraph($workspace->workspaceName)->findNodeAggregateById(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,23 +36,21 @@
<f:switch expression="{true}">
<f:case value="{inaccessibleRelation.workspace.personalWorkspace}">
<i class="fas fa-user"
title="{neos:backend.translate(id: 'workspaces.personalWorkspace', source: 'Modules', package: 'Neos.Neos')}"
title="{neos:backend.translate(id: 'workspaces.personalWorkspace', source: 'Main', package: 'Neos.Workspace.Ui')}"
data-neos-toggle="tooltip"></i>
{neos:backend.translate(id: 'workspaces.personalWorkspace', source: 'Modules', package: 'Neos.Neos')}
{neos:backend.translate(id: 'workspaces.personalWorkspace', source: 'Main', package: 'Neos.Workspace.Ui')}
</f:case>
<f:case value="{inaccessibleRelation.workspace.privateWorkspace}">
<i class="fas fa-shield"
title="{neos:backend.translate(id: 'workspaces.privateWorkspace', source: 'Modules', package: 'Neos.Neos')}"
title="{neos:backend.translate(id: 'workspaces.privateWorkspace', source: 'Main', package: 'Neos.Workspace.Ui')}"
data-neos-toggle="tooltip"></i>
{neos:backend.translate(id: 'workspaces.privateWorkspace', source: 'Modules', package:
'Neos.Neos')}
{neos:backend.translate(id: 'workspaces.privateWorkspace', source: 'Main', package: 'Neos.Workspace.Ui')}
</f:case>
<f:case value="{inaccessibleRelation.workspace.internalWorkspace}">
<i class="fas fa-group"
title="{neos:backend.translate(id: 'workspaces.internalWorkspace', source: 'Modules', package: 'Neos.Neos')}"
title="{neos:backend.translate(id: 'workspaces.internalWorkspace', source: 'Main', package: 'Neos.Workspace.Ui')}"
data-neos-toggle="tooltip"></i>
{neos:backend.translate(id: 'workspaces.internalWorkspace', source: 'Modules', package:
'Neos.Neos')}
{neos:backend.translate(id: 'workspaces.internalWorkspace', source: 'Main', package: 'Neos.Workspace.Ui')}
</f:case>
<f:defaultCase>
---
Expand Down Expand Up @@ -96,8 +94,8 @@
<f:if condition="{nodeInformation.documentNode}">
<f:then>
<neos:link.node node="{nodeInformation.documentNode}" target="_blank"
title="{neos:backend.translate(id: 'workspaces.openPageInWorkspace', source: 'Modules', package: 'Neos.Neos', arguments: {0: nodeInformation.workspace.workspaceTitle.value})}">
<span title="{f:render(partial: 'Module/Shared/DocumentBreadcrumb', arguments: {node: nodeInformation.documentNode})}" data-neos-toggle="tooltip">{nodeInformation.documentNode.label}</span>
title="{neos:backend.translate(id: 'workspaces.openPageInWorkspace', source: 'Main', package: 'Neos.Workspace.Ui', arguments: {0: nodeInformation.workspace.workspaceTitle.value})}">
<span title="{f:render(partial: 'Module/Shared/DocumentBreadcrumb', arguments: {node: nodeInformation.documentNode})}" data-neos-toggle="tooltip">{neos:node.label(node: nodeInformation.documentNode)}</span>
<i class="fas fa-external-link-alt"></i>
</neos:link.node>
</f:then>
Expand All @@ -113,7 +111,7 @@
title="{f:if(condition: nodeInformation.node.nodeType.label, then: '{neos:backend.translate(id: nodeInformation.node.nodeType.label, package: \'Neos.Neos\')}', else: '{nodeInformation.node.nodeType.name}')}"
data-neos-toggle="tooltip" data-placement="left"></i>
</f:if>
<span title="{nodeInformation.node.path}" data-neos-toggle="tooltip" data-placement="left">{nodeInformation.node.label}</span>
<span title="{nodeInformation.node.path}" data-neos-toggle="tooltip" data-placement="left">{neos:node.label(node: nodeInformation.node)}</span>
</td>
<td>
<f:if condition="{contentDimensions}">
Expand All @@ -124,19 +122,19 @@
<f:if condition="{userWorkspace} == {nodeInformation.workspace}">
<f:then>
<i class="fas fa-user"
title="{neos:backend.translate(id: 'workspaces.personalWorkspace', source: 'Modules', package: 'Neos.Neos')}"
title="{neos:backend.translate(id: 'workspaces.personalWorkspace', source: 'Main', package: 'Neos.Workspace.Ui')}"
data-neos-toggle="tooltip"></i>
</f:then>
<f:else>
<f:if condition="{nodeInformation.workspace.privateWorkspace}">
<f:then>
<i class="fas fa-shield"
title="{neos:backend.translate(id: 'workspaces.privateWorkspace', source: 'Modules', package: 'Neos.Neos')}"
title="{neos:backend.translate(id: 'workspaces.privateWorkspace', source: 'Main', package: 'Neos.Workspace.Ui')}"
data-neos-toggle="tooltip"></i>
</f:then>
<f:else>
<i class="fas fa-group"
title="{neos:backend.translate(id: 'workspaces.internalWorkspace', source: 'Modules', package: 'Neos.Neos')}"
title="{neos:backend.translate(id: 'workspaces.internalWorkspace', source: 'Main', package: 'Neos.Workspace.Ui')}"
data-neos-toggle="tooltip"></i>
</f:else>
</f:if>
Expand Down
88 changes: 88 additions & 0 deletions Neos.Neos/Classes/AssetUsage/AssetUsageIndexingProcessor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<?php

declare(strict_types=1);

namespace Neos\Neos\AssetUsage;

use Neos\ContentRepository\Core\ContentRepository;
use Neos\ContentRepository\Core\NodeType\NodeTypeName;
use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindChildNodesFilter;
use Neos\ContentRepository\Core\Projection\ContentGraph\Node;
use Neos\ContentRepository\Core\Projection\ContentGraph\VisibilityConstraints;
use Neos\ContentRepository\Core\SharedModel\Exception\NodeAggregateCurrentlyDoesNotExist;
use Neos\ContentRepository\Core\SharedModel\Exception\WorkspaceDoesNotExist;
use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName;
use Neos\Neos\AssetUsage\Service\AssetUsageIndexingService;

readonly class AssetUsageIndexingProcessor
{
public function __construct(
private AssetUsageIndexingService $assetUsageIndexingService
) {
}

/**
* @param callable(string $message):void|null $callback
*/
public function buildIndex(ContentRepository $contentRepository, NodeTypeName $nodeTypeName, callable $callback = null): void
{
$variationGraph = $contentRepository->getVariationGraph();

$workspaceFinder = $contentRepository->getWorkspaceFinder();
$liveWorkspace = $workspaceFinder->findOneByName(WorkspaceName::forLive());
if ($liveWorkspace === null) {
throw WorkspaceDoesNotExist::butWasSupposedTo(WorkspaceName::forLive());
}

$this->assetUsageIndexingService->pruneIndex($contentRepository->id);

$workspaces = [$liveWorkspace];

$this->dispatchMessage($callback, sprintf('ContentRepository "%s"', $contentRepository->id->value));
while ($workspaces !== []) {
$workspace = array_shift($workspaces);

$contentGraph = $contentRepository->getContentGraph($workspace->workspaceName);
$this->dispatchMessage($callback, sprintf(' Workspace: %s', $contentGraph->getWorkspaceName()->value));

$dimensionSpacePoints = $variationGraph->getDimensionSpacePoints();

$rootNodeAggregate = $contentGraph->findRootNodeAggregateByType(
$nodeTypeName
);
if ($rootNodeAggregate === null) {
$this->dispatchMessage($callback, sprintf(' ERROR: %s', "Root node aggregate was not found."));
continue;
}
$rootNodeAggregateId = $rootNodeAggregate->nodeAggregateId;

foreach ($dimensionSpacePoints as $dimensionSpacePoint) {
$this->dispatchMessage($callback, sprintf(' DimensionSpacePoint: %s', $dimensionSpacePoint->toJson()));

$subgraph = $contentGraph->getSubgraph($dimensionSpacePoint, VisibilityConstraints::withoutRestrictions());
$childNodes = iterator_to_array($subgraph->findChildNodes($rootNodeAggregateId, FindChildNodesFilter::create()));

while ($childNodes !== []) {
/** @var Node $childNode */
$childNode = array_shift($childNodes);
if (!$childNode->originDimensionSpacePoint->equals($childNode->dimensionSpacePoint)) {
continue;
}
$this->assetUsageIndexingService->updateIndex($contentRepository->id, $childNode);
array_push($childNodes, ...iterator_to_array($subgraph->findChildNodes($childNode->aggregateId, FindChildNodesFilter::create())));
}
}

array_push($workspaces, ...array_values($workspaceFinder->findByBaseWorkspace($workspace->workspaceName)));
}
}

private function dispatchMessage(?callable $callback, string $value): void
{
if ($callback === null) {
return;
}

$callback($value);
}
}
28 changes: 28 additions & 0 deletions Neos.Neos/Classes/AssetUsage/AssetUsageService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

declare(strict_types=1);

namespace Neos\Neos\AssetUsage;

use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryId;
use Neos\Flow\Annotations as Flow;
use Neos\Neos\AssetUsage\Domain\AssetUsageRepository;
use Neos\Neos\AssetUsage\Dto\AssetUsageFilter;
use Neos\Neos\AssetUsage\Dto\AssetUsages;

/**
* Central authority to look up or remove asset usages in specific a ContentRepository
*/
#[Flow\Scope('singleton')]
class AssetUsageService
{
public function __construct(
private readonly AssetUsageRepository $assetUsageRepository,
) {
}

public function findByFilter(ContentRepositoryId $contentRepositoryId, AssetUsageFilter $filter): AssetUsages
{
return $this->assetUsageRepository->findUsages($contentRepositoryId, $filter);
}
}
2 changes: 1 addition & 1 deletion Neos.Neos/Classes/AssetUsage/AssetUsageStrategy.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public function getUsageReferences(AssetInterface $asset): array
$convertedUsages[] = new AssetUsageReference(
$asset,
ContentRepositoryId::fromString($contentRepositoryId),
$usage->contentStreamId,
$usage->workspaceName,
$usage->originDimensionSpacePoint,
$usage->nodeAggregateId
);
Expand Down
Loading

0 comments on commit 88e344d

Please sign in to comment.