propelorm/Propel

Propel 1.7 OutOfMemoryException from cross-ref add

jwong-dayspring opened this issue · 0 comments

I have a CrossRef table users_roles that joins my users and roles tables. Propel generates User::addRole() and Role::addUser() functions in the Base object.

With a large dataset, calling User::addRole() results in PHP running out of memory. The same code works just fine with a smaller dataset, or with Propel 1.6.x.

Propel 1.7 sets the back reference when adding on a CrossRef object. In my project, this adds a $role->getUsers() call to User::doAddRole(). Adding a role to a user ends up fetching all users that with that role.

In my case, I don't need the back reference counts to be updated. Since the problem code is in the Base class, I was able to override doAddRole() in the subclass.

I replaced the generated code:

protected function doAddRole(Role $role)
    {
        // set the back reference to this object directly as using provided method either results
        // in endless loop or in multiple relations
        if (!$role->getUsers()->contains($this)) { $userRole = new UserRole();
        $userRole->setRole($role);
        $this->addUserRole($userRole);

            $foreignCollection = $role->getUsers();
            $foreignCollection[] = $this;
        }
    }

with (same as what Propel 1.6.x generated):

protected function doAddRole(Role $role)
    {
        $userRole = new UserRole();
        $userRole->setRole($role);
        $this->addUserRole($userRole);
    }

Initially it didn't seem like $foreignCollection was necessary, but it updates the PropelObjectCollection held by Role and subsequent calls to getUsers() returns the updated collection, including the User the role was just added to.

I can see why setting the back reference is helpful, but #677/#678 introduces a nasty side-effect for lookup table relationships and large databases.

See PHP5ObjectBuilder::addCrossFKDoAdd()