Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OneToMany not syncing with Eloquent Driver #43

Open
swen4 opened this issue Sep 10, 2024 · 2 comments
Open

OneToMany not syncing with Eloquent Driver #43

swen4 opened this issue Sep 10, 2024 · 2 comments

Comments

@swen4
Copy link

swen4 commented Sep 10, 2024

I cannot seem to get my collectons to sync using a OneToMany relationship. I'm using eloquent driver with the following setup:

  • Entries are in database
  • Blueprints are in files

My two collections are as follows:

  • Collection handle: articles -> revisions enabled
  • Collection handle: quotes

I'm trying to set up the following relationship:

public function boot(): void
{
    /**
     * Entry relationships between articles and quotes
     */
    Relate::OneToMany(
        'quotes.article',
        'articles.quotes'
    );
}
  • Quotes can be linked to an article
  • An article can have many quotes

My blueprints have the following fields:

article.yaml

-
  handle: quotes
  field:
    mode: default
    create: true
    collections:
      - quotes
    display: Quotes
    type: entries
    listable: true

quote.yaml

-
  handle: article
  field:
    max_items: 1
    type: entries
    mode: default
    collections:
      - articles
    display: Artikel
    listable: true

Output of php please relate:list

+---+--------------------+--------------------+------------------+---------------+-------------------+--------------+----------------+-----------------------+
|   | Primary Collection | Related Collection | Primary Field    | Related Field | Relationship      | With Events? | Allow Deletes? | Is Automatic Inverse? |
+---+--------------------+--------------------+------------------+---------------+-------------------+--------------+----------------+-----------------------+
| 1 | [entry].quotes     | [entry].article    | [entry].articles | quotes        | Many to One (*-1) | Yes          | Yes            | No                    |
| 2 | [entry].articles   | [entry].quotes     | [entry].quotes   | article       | One to Many (1-*) | Yes          | Yes            | Yes (1)               |
+---+--------------------+--------------------+------------------+---------------+-------------------+--------------+----------------+-----------------------+

Some observations:

  • In the output of relate:list, it looks like the values for "related collection", "primary field" and "related field" might be wrong, using singular/plural incorrectly.
  • The synchronization doesn't happen either way. Adding a quote to an article doesn't sync, and adding an article to a quote doesn't sync
  • The output of php please relate:fill shows:
Updating relationships. This may take a while if you have a lot of entries.

Updating relationship: (1-*) [articles.quotes quotes.article]...
Updating relationship: (1-*) [articles.quotes quotes.article]... done!

Is there a misconfiguration on my part, or is there a potential bug at play?

@ajcsilva
Copy link

I'm also dealing with this issue. I did some digging and found a couple things:

In src/Processors/RelationshipProcessor.php on line 248, an array of effectedEntries is being created and should be keyed by the entry's id. Dumping this array on the next line will show that the id is reindexed and the entry is lost. According to this stackoverflow answer it could be because a numeric id (when using the database driver) is seen as an integer by array_merge and reindexes it.

$this->effectedEntries = array_merge(
      $this->effectedEntries,
      $entries->keyBy('id')->all()
  );

This leads to an issue in shouldProcessRelationship function on line 353. It is searching for the entry's id using array_key_exists but because it has been reindexed, it never finds it.

  if ($relationship->rightType == 'entry' && ! array_key_exists($id, $this->effectedEntries)) {
      return false;
  }

I tested out replacing array_key_exists with array_replace and solved this particular issue, though I don't know it's effect on flat file drivers, etc.

This lead to another issue though. After the update, saving an entry with a relationship did not work. I would link an entry using the CP but after it saved, the entry would just disappear. So I looked a little further and it seems to be an issue in src/Processors/Concerns/ProcessesOneToMany.php in the foreach loop. It looks like the array_search is removing the entry and then saving it. I'm not sure what is suppose to be happening here.

  foreach ($results->added as $addedId) {
      if ($this->shouldProcessRelationship($relationship, $addedId)) {
          $this->dependencies[] = $addedId;
          $dependent = Data::find($this->getDependency($relationship, $addedId));

          if ($this->withDependent && $dependent !== null && $inverse = $relationship->getInverse()) {
              $leftReference = $dependent->get($relationship->leftField);

              if (($key = array_search($addedId, $leftReference)) !== false) {
                  unset($leftReference[$key]);
                  $dependent->set($relationship->leftField, array_values($leftReference));
                  $dependent->saveQuietly();
              }
          }

          $this->setFieldValue($relationship, $this->getEffectedEntity($relationship, $addedId));
      }
  }

@robdekort
Copy link

It seems I'm running into this as well, although I'm seeing the issue (using Eloquent) with a one to many relationship between entries and users.

I've also seen examples of users getting related to entries that shouldn't be related. So something must definitely be off here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants