Download the PHP package malef/associate without Composer

On this page you can find all versions of the php package malef/associate. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package associate

Build Status Scrutinizer Code Quality Latest Stable Version Total Downloads Monthly Downloads License

Table of contents

Introduction

This library provides optimizations for entity fetching for Doctrine ORM to address N+1 queries problem. It plays especially nicely with Deferred implementation from webonyx/graphql-php allowing to significantly reduce number of database queries.

License

This bundle is under the MIT license. See the complete license in LICENSE file.

Getting started

Include this bundle in your project using Composer as follows (assuming it is installed globally):

For more information on Composer see its Introduction.

To get the instance of EntityLoader for your entity manager you can use the facade provided with the library. For more complex cases you will also need instances of AssociationTreeBuilder which can be instantiated with new or using the facade.

You can also use these classes for defining services appropriate for DI container your framework of choice uses.

That's all - now you're ready to go!

Usage examples

Efficiently loading associated entities and solving N+1 queries problem

Rationale

Let's assume that we're building an e-commerce website using doctrine/orm for persistence. One of the problems we'll run into is N+1 queries problem. It occurs when we fetch some entities from database and then attempt to traverse their associations via getters (e.g. during their serialization).

To give an example, we may have some products that we need to list. Each of them has few variants that we also need to display. If we simply provide this set of products to our template (or serializer, if we're providing some API) then variants for each product will be fetched separately when we try to access the corresponding PersistentCollection managed by Doctrine ORM for the first time. While this will work fine it will incur one SELECT query for each Product instance provided. Hence if we want to list 100 products this way we will end up with 101 database queries being executed, and this number will increase further if we need to follow more relationships.

Some ORMs are addressing this problem for some basic cases. For instance in Eloquent ORM you can use Lazy Eager Loading. It is still limited to traversing only one relationship at a time though. Sadly, Doctrine ORM doesn't provide a similar helper.

You can find out more about this problem at 5 Doctrine ORM Performance Traps You Should Avoid written by Benjamin Eberlei - see section titled in section Lazy-Loading and N+1 Queries. Four ways to address this problem are pointed out there.

Eager loading (solution 3) can be the simplest way to go but in many cases we will find it too rigid. The problem is that it will load the related entities every time and often we need to access then just in few specific cases.

Other solutions are more flexible, like using dedicated DQL query (solution 1) or triggering eager loading of entities after collecting their identifiers (solution 2). These solutions would however result in clunky code and they have to be adjusted depending on whether given association is of -to-one or -to-many type and whether entities that are already initialized are on the inverse or the owning side of the association. Additionally we sometimes need to join other entities for filtering purposes and we cannot simply fetch everything that is needed in a single query as the result set that needs to be hydrated by Doctrine ORM would become to large. Finally some minor optimizations can be applied if some \Doctrine\Common\Persistence\Proxy instances or \Doctrine\ORM\PersistentCollection instances are already initialized and hence can be skipped.

This library tries to implement solutions 1 and 2 but in a clean and encapsulated manner that is easy to use in multiple scenarios.

Basic usage

In the example above it would be only required to precede previously given code with:

After executing this snippet all variants for given products will be loaded with a single SELECT query and calling getVariants will not result in any additional queries.

Possible input arguments

Malef\Associate\DoctrineOrm\Loader\EntityLoader::load method accepts following arguments:

Input arguments for methods analogous to EntityLoader::load (like Malef\Associate\DoctrineOrm\Loader\DeferredEntityLoader::createDeferred and Malef\Associate\DoctrineOrm\Loader\DeferredEntityLoaderFactory::create) accept similar arguments.

Loading over multiple relationships

If using dot-separated string, or an array of strings as $associations argument it is possible to load entities following multiple associations in sequence. Assuming we have a Product entity with many Variants, and these in turn have multiple Offers available, we can use following values as $associations:

This will allow us later to use methods like $product->getVariants() or $product->getVariants()->getOffers() without incurring any additional queries.

If we want to follow multiple multiple associations that are not sequential (i.e. they diverge somehov into multiple paths) our only option is to use Malef\Associate\DoctrineOrm\Association\AssociationTree. Assuming that for Offer entity we have one Seller and multiple Bidders we could use following code:

This way we could also call $product->getVariants()->getOffers()->getSeller() and $product->getVariants()->getOffers()->getBidders() without incurring any additional queries.

Chunking

If the number of products or associated entities is high then they'll be split in chunks and associations for each chunk will be loaded separately. Chunk size is set by default to 1000 but you are free to alter it, or set it to null to disable chunking.

Limitations

Important! It's not possible to reduce the number of queries for one-to-one associations when starting from inverse side - Doctrine ORM loads them by default issuing a separate SELECT for each entity. To address this case you may consider changing such association to one-to-many (and use this library afterwards) or using embeddable if possible (in which case embedded entities will be loaded with the same query that loads entities that contain them).

Deferring association traversal to load entities in bulk

If you're working on a project using Doctrine ORM and providing GraphQL API then this library can play nicely with Deferred class provided by webonyx/graphql-php. You can read more about the general idea behind this approach at Solving N+1 Problem section of its documentation.

Let's assume we need to implement resolve function that will return Variant instances for Product instance. Basic implementation could look as follows:

But using this approach we would again end up with N+1 queries executed against our database. To alleviate this problem and to load these objects efficiently we can use instance of DeferredEntityLoader like this:

Et voilà! What DeferredEntityLoader will do here is it will accumulate all entities while GraphQL query result is build width first. When GraphQL library attempts to resolve Deferred that was returned in our resolve function the collector will use EntityLoader to load all entities as efficiently as possible based on association tree provided before.


All versions of associate with dependencies

PHP Build Version
Package Version
Requires php Version ^7.2
symfony/property-access Version ^3.0|^4.0|^5.0
nicmart/tree Version ^0.2.7
symfony/options-resolver Version ^3.0|^4.0|^5.0
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package malef/associate contains the following files

Loading the files please wait ....