Download the PHP package andanteproject/shared-query-builder without Composer

On this page you can find all versions of the php package andanteproject/shared-query-builder. 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 shared-query-builder

Andante Project Logo

Shared Query Builder

Doctrine 2/3 Query Builder decorator - AndanteProject

Latest Version Github actions Php8 PhpStan

A Doctrine 2 Query Builder decorator that makes it easier to build your query in shared contexts.

Table of contents

Why do I need this?

When your query business logic is big and complex you are probably going to split its building process to different places/classes.

Without SharedQueryBuilder there is no way to do that unless guessing Entity aliases and messing with join statements.

This query builder decorator addresses some problems you can find in a real world situation you usually solve with workarounds and business conventions.

Features

Requirements

Doctrine 3 and PHP 8.0 or higher.

Install

Via Composer:

Set up

After creating your query builder, wrap it inside our SharedQueryBuilder.

From now on, you can use $sqb exactly as you usually do with query builder (every single method of QueryBuilder is available on SharedQueryBuilder), but with some useful extra methods 🤫.

When you're done building your query, just unwrap your SharedQueryBuilder.

Please note:

Which additional methods do I have?

Entity methods

You can ask the SharedQueryBuilder if it has and entity in the from statement or some join statements.

You can ask which is the alias of an Entity inside the query you're building (no matter if it is used in a from statement or a join statement).

You can use withAlias method to smoothly add a condition for that entity property:

Given an alias, you can retrieve its entity class:

QueryBuilder::getAllAliases is extended to have an optional bool argument $includeLazy (default:false) to include lazy joins aliases.

Lazy joins

All query builder join methods can be used as usual, but you can also use them with "lazy" prefix.

By doing this, you are defining a join statement without actually adding it to your DQL query. It is going to be added to your DQL query only when you add another condition/dql part which refers to it. Automagically ✨.

Based on how confused you are right now, you can check why you should need this or some examples to achieve your "OMG" revelation moment.

Proposals

When you split query building across multiple strategies or filter classes, you often want each one to contribute a block of logic: several conditions, joins, parameters, and maybe select/groupBy/orderBy/having. Proposals let you collect that block in a temporary object and “merge” it into the main SharedQueryBuilder in one go—by using the proposal inside andWhere, orWhere, where, andHaving, or orHaving. There is no separate merge() call: merging happens when the proposal is used in one of those methods.

Creating a proposal

Create an empty proposal from the SharedQueryBuilder; you can give it a name (useful for debugging) or leave it empty to get a unique auto-generated name.

Collect API (no side effects until use)

A proposal exposes the same method names as the SQB for building a local set of conditions, joins, parameters, and other parts. Nothing is written to the main query until the proposal is used in an expression. Build conditions with the proposal’s expr() (e.g. eq, neq, andX, orX) so they stay object-oriented. Never hardcode entity aliases—use the SQB’s withAlias(Entity::class, 'property') (or the proposal’s, which delegates to the SQB) so the library resolves the correct alias.

Merging by use

To merge a proposal into the main query, pass it to andWhere, orWhere, where, andHaving, or orHaving. The SQB will expand the proposal (apply its joins, parameters, select/groupBy/orderBy/having, build the condition, and replace the proposal with the resulting DQL).

You can combine multiple proposals in an OR (or AND) by passing the proposals directly to expr()->orX() (or expr()->andX()). The SQB expands them when building the where clause; you do not need to call expandInto().

Consumed state and reuse

After a proposal is expanded for the first time, it is marked consumed. Using the same proposal again in another andWhere/orWhere is a no-op: it expands to a neutral 1=1 so the query result is unchanged. Cloning a proposal gives a non-consumed copy with the same collected state.

Introspection and clear

Example: filter receives a proposal, fills it, returns it; merge at upper level

The caller (e.g. controller) creates an empty proposal and passes it to the filter. The filter receives the request and that proposal; it fills the proposal using the proposal’s methods (e.g. withAlias(Entity::class, 'property'), which delegates to the SQB) so aliases are never hardcoded, then returns the same proposal. The caller is responsible for merging the proposal into the query. That way the filter only builds its block of logic; where and how it is combined (e.g. andWhere vs orWhere) stays at the upper level.

This keeps the filter responsible only for building its conditions and parameters (using withAlias so the library resolves entity aliases); the caller decides how to merge and avoids alias or parameter name clashes between filters.

Examples

Let's suppose we need to list User entities but we also have an optional filter to search a user by their address Building name.

There is no need to perform any join until we decide to use that filter. We can use Lazy Join to achieve this.

You are probably thinking: why don't we achieve the same result with the following, more common, way? (keep in mind that avoiding unnecessary joins is still a requirement)

The code above is perfectly fine if you build this whole query in the same context:

But you have problems:

A real world case

If your query structure grows with lots of joins and filtering criteria, you are probably going to split all that business logic in different classes.

For instance, in a backoffice Users list, you are probably going to define your main query to list entities in your controller and handle optional filters in some other classes.

Filter classes may look like this:

We are committing some multiple sins here! 💀 The context is changed.

That's why SharedQueryBuilder is going to save your ass in these situations

Let's see how we can solve all these problems with SharedQueryBuilder (you can now guess why it is named like this).

Using SharedQueryBuilder you can:

Filter classes will look like this:

Evolution: filters that receive and return a Proposal

You can go one step further: have each filter receive an empty Proposal (created by the caller), fill it using withAlias() and the proposal’s expr(), and return that proposal. The controller then merges each proposal (e.g. with andWhere) at the upper level. That keeps the same benefits (no hardcoded aliases, merge logic in one place) and makes each filter a pure “block builder” that never touches the SQB’s where clause directly.

Step 1: BuildingNameFilter receives and returns a Proposal

Step 2: Controller creates proposals, passes them to both filters, merges at upper level

Immutable Parameters

Shared query builder has Immutable Parameters. Once defined, they cannot be changed; otherwise an Exception will be raised.

Set parameter and use it in expression at the same moment

If you are sure you are not going to use a parameter in multiple places inside your query, you can write the following code 🙌

this way 👇👇👇

Unique parameters

Beside immutable parameters, you can also demand query builder the generation of a parameter name. Using the following methods, query builder will decorate names to avoid conflicts with already declared ones ( which cannot even happen with immutable parameters).

Conclusion

The world is a happier place 💁.

Give us a ⭐️ if your world is now a happier place too! 💃🏻

Built with love ❤️ by AndanteProject team.


All versions of shared-query-builder with dependencies

PHP Build Version
Package Version
Requires php Version ^8.0
doctrine/orm Version ^3.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 andanteproject/shared-query-builder contains the following files

Loading the files please wait ...