Currently pointers are an arbitrary class with data stored in a key/value store. We want to convert these to become a content entity type.

The pointer field would become a dynamic entity reference field (adding a dependency on https://www.drupal.org/project/dynamic_entity_reference), so that a pointer can reference either a local workspace, or a remote config entity.

We would also need to add another text field to store the workspace name, in the case of remote workspaces that only reference a remote config entity.

Some (but not all?) places in the code base that needs updating is:

  • The pointer class itself
  • workspace_install()
  • workspace_workspace_insert()
  • relaxed_cron()
  • \Drupal\relaxed\Entity\Remote::postSave()
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

dixon_ created an issue. See original summary.

Crell’s picture

Assigned: Unassigned » Crell

I volunteer as tribute!

Crell’s picture

Still in progress work. Mainly just creating the entity, haven't done anything with it yet. If someone wants to work on this over the weekend, feel free.

CNR more on principle than anything else...

dixon_’s picture

Copy/paste from IRC brain dump:

1:18 AM  Crell: timmillwood: I think we should do a slight adjustment to the ticket regarding Pointers. In don't like idea of using a dynamic entity reference to reference a workspace content entity (in case of local pointer) or a remote config entity (in case of remote pointer)

1:18 AM  Instead I think a pointer should have two main fields

1:19 AM  1. Entity reference to a remote config entity (only)

1:19 AM  2. Workspace name

1:19 AM  Then we create a remote entity that simply points to the local system

1:20 AM  This way both local and remote pointers work the same way

1:20 AM  I like that symmetry rather than messing around with two different types of references that needs to be handled differently
timmillwood’s picture

@dixon_ and I spoke about this, this morning. Forcing pointers to only reference Remote entities would force us to move Remote entities into Workspace module, when they are not needed. Only uses with relaxed need Remote entities, it seems a bit of overkill. I think the current implementation sounds more straight forward.

@Crell - Patch looks good so far.

+++ b/src/Entity/WorkspacePointer.php
@@ -0,0 +1,111 @@
+ *   handlers = {
+ *     "access" = "Drupal\workspace\WorkspacePointerAccessControlHandler",
+ *   },

I think this can be removed.

timmillwood’s picture

@Crell - After speaking to @dixon_ we think it might be simpler to remove the dependency on Dynamic entity reference, and just use a workspace entity reference field instead, then Relaxed module (or any other contrib module) can add extra fields for their use case. In the applies method of the replicator it will just check that the pointer has the fields that it needs.

Crell’s picture

Just checkpointing more work. Switched to an ER, and now there's a test! :-)

There's also an existing WorkspacePointer class and interface that is totally not what I'm adding here. It's a front for the keyvalue store. It will get refactored out of existence soon, but for now I've renamed it to WorkspacePointerTracker[Interface] to avoid the names colliding and wasting hours of my time trying to figure out why the container was exploding when I tried to run any test at all. *ahem*

No interdiff because I had to do some weird rebase stuff to fix the previous, making an interdiff not particularly viable.

Crell’s picture

OK, architecture question.

Currently, Pointer is a dumb struct in a keyvalue store, indexed by the ID of the workspace it's pointing FROM and containing the ID of the workspace it's pointing TO. That means we can always look up, from a workspace, what its parent is.

However, what the code is currently doing is this (from WorkbenchModerationSubscriber, but also appears in the Rules plugin):

$parent_workspace = $workspace->get('upstream')->entity;

/** @var PointerInterface $source_pointer */
$source_pointer = $this->workspacePointerTracker->get('workspace:' . $workspace->id());
/** @var PointerInterface $target_pointer */
$target_pointer = $this->workspacePointerTracker->get('workspace:' . $parent_workspace->id());

$this->replicatorManager->replicate($source_pointer, $target_pointer);

That is, the source workspace already knows its target workspace directly, so we're loading both of those, then using that to look up the pointer objects, and then passing those to the replicator which simply dereferences back to the workspaces. Which is kind of silly.

This issue switches Pointer to a content entity, WorkspacePointer. That means it has its own ID, and a target (now represented by an ER field, at least by default). However, that means we cannot easily look up a pointer from a workspace; we'd have to use an EntityQuery and a back-reference, ie, "find WP objects that point to me", which is not guaranteed semantically to be unique.

But that also makes the indirection above kind of pointless (no pun intended). Rather, we should change Workspace to have an ER field to a WorkspacePointer, and therefore change the UI accordingly, too. That would allow us to get the $target_pointer simply with $workspace->get('pointer')->entity. However, we still don't have the source pointer without doing a reverse lookup, because we already have a resolved workspace in this event.

But since the replicator nominally allows for remote-to-remote replication, it doesn't make sense to have it take $source_workspace and $target_pointer, since at least in the abstract it should work with 2 pointers.

Tixon (Tim + Dixon), I am not sure how to proceed at this point. Your input is requested. :-)

Edit: I've no idea why syntax highlighting is not working on this snippet...

timmillwood’s picture

@Crell - @Dixon_ and I have already discussed that the upstream field on a Workspace entity should become an ER to a Pointer entity rather than a Workspace entity. Not only does this fix the issue you describe, this also allows for an upstream to be a remote workspace (or remote CouchDB database, or whatever).

In Deploy we won't have this issue, because it does replication via a Replication entity, which will reference a source and target Pointer entity.

In the WBM and Rules integration it's based of a Workspace entity, so as you said we need a reverse lookup, should this not simply be:

$pointers = $this->entityTypeManager->getStorage('pointer')->loadByProperties(['workspace' => $workspace->id()]);
$source_pointer = reset($pointers);
dixon_’s picture

I think we should include in this issue the change on the upstream field to become a reference to Pointers, instead of directly to Workspaces. After doing so I think we can remove WorkspacePointerTracker entirely.

Crell’s picture

The reverse lookup is possible, surely. It's more that it's not guaranteed to be unique, and I'm not entirely certain how it gets created, so I'm not sure how much I should be stressing over it.

Crell’s picture

OK, let's try this. I have not actually tried running this code yet, so the odds of it exploding completely are high. :-) But it's another checkpoint for code review and I need to shift gears anyway.

With Tim's permission I moved a fair bit of code from the .module file to services and refactored that to follow the same pattern as Workbench Moderation uses, complete with functional-style methods. I also removed all pass-by-ref objects, because in PHP that's pretty much never, ever what you want to do.

I think this is what we are looking for. Assuming it gets a thumbs up from Tixon, the next step is to make sure it all actually, um, works. :-)

timmillwood’s picture

@crell - awesome, thanks, I've made a number of updates:
- Switch source and target on the Replication entity to be entity references to workspace_pointer
- Make the WorkspacePointer entity not Multiversionable, but revisionable
- Change the workspace field on WorkspacePointer to workspace_pointer to make sure it doesn't clash with the workspace field multiversion adds. Even though it shouldn't because I have made WorkspacePointer not multiversionable.
- Change the default name of WorkspacePointer entities to $workspace->label() . ' workspace' so it looks better in the form Deploy module adds, and to hide that pointers exist from the end user.
- Updated WBM and Rules integration to use the correct entity and field names.
- Update WorkspaceListBuilder to fix an unrelated bug which I should've fixed in a separate issue but fixed it here as I saw it.
- Removed dependency on Dynamic Entity Reference
- Fix install to add WorkspacePointer entities for existing workspaces
- Fix hook_entity_base_field_info to return something

  • timmillwood committed 7cd737e on 8.x-1.x authored by Crell
    Issue #2683265 by Crell, timmillwood: Convert pointers to a content...
timmillwood’s picture

Status: Needs review » Fixed

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

The last submitted patch, 3: 2683265-pointer-entity.patch, failed testing.

The last submitted patch, 3: 2683265-pointer-entity.patch, failed testing.

The last submitted patch, 7: 2683265-pointer-entity.patch, failed testing.

The last submitted patch, 7: 2683265-pointer-entity.patch, failed testing.

The last submitted patch, 12: 2683265-pointer-entity.patch, failed testing.

The last submitted patch, 12: 2683265-pointer-entity.patch, failed testing.

Status: Closed (fixed) » Needs work

The last submitted patch, 13: convert_pointers_to_a-2683265-13.patch, failed testing.

The last submitted patch, 13: convert_pointers_to_a-2683265-13.patch, failed testing.

The last submitted patch, 3: 2683265-pointer-entity.patch, failed testing.

The last submitted patch, 7: 2683265-pointer-entity.patch, failed testing.

The last submitted patch, 12: 2683265-pointer-entity.patch, failed testing.

The last submitted patch, 13: convert_pointers_to_a-2683265-13.patch, failed testing.

timmillwood’s picture

Status: Needs work » Closed (fixed)