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

Support for Join conditions #122

Closed
wants to merge 2 commits into from
Closed

Conversation

ju1ius
Copy link

@ju1ius ju1ius commented Aug 20, 2015

This:

Spec::join('users', 'user', null, Spec::andx(
    Spec::eq('active', true),
    Spec::eq('status', 'somestatus')
))

Will be equivalent to:

$qb->join('foo.users', 'user', 'WITH', $qb->expr()->andX(
    $qb->expr()->eq('user.active',  true),
    $qb->expr()->eq('user.status', 'somestatus')
));

*/
public function __construct($field, $newAlias, $dqlAlias = null)
public function __construct($field, $newAlias, $dqlAlias = null, $condition = null, $conditionType = null)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't it be the other way around? The signature of the QueryBuilder::join is:

public function join($join, $alias, $conditionType = null, $condition = null, $indexBy = null);

I think we should have it in the same order.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I chose this order because 90% of the time I don't need to change the default ON clause.
It makes the api less verbose, but on the other hand it's not as expressive and diverges from Doctrine, so it might be confusing...

Maybe we should keep it the doctrine way, and add a new method to the builder, like

Spec::with($field, $newAlias, $joinType, $joinCondition);

While we're at it we could also solve the problem that it's currently impossible to do fetch joins with the spec builder:

namespace Happyr\DoctrineSpecification\Query;

class With extends AbstractJoin
{
    protected $joinType;

    public function __construct ($field, $newAlias, $joinType='join',  $condition=null) 
    {
        $parentAlias = substr($field, 0, strpos($field, '.'));
        $this->joinType = $joinType;
        parent::__construct($field, $newAlias, $parentAlias ?: null, 'WITH', $condition);
    }

    public function modify(QueryBuilder $qb, $dqlAlias)
    {
        $dqlAlias = $this->dqlAlias ?: $dqlAlias;
        $join = $this->joinType;
        $condition = $this->getJoinCondition($this->condition, $qb);
        $qb
            ->addSelect($this->newAlias) // FETCH THAT JOIN !!!
            ->$join("{$dqlAlias}.{$this->field}", $this->newAlias, 'WITH', $condition)
        ;
    }
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree what the order doctrine uses is verbose. But it makes sense because it is easier to read and understand.

I don't really like the idea with new With, those kind of shortcuts should be in the factory. I suggest changing the constructor to be the same as Doctrine and then add a factory method which covers the 90% of the use cases:

public static function joinWith($field, $newAlias, $condition, $dqlAlias = null, $conditionType = null)
{
    return new Join($field, $newAlias, $dqlAlias, $conditionType, $condition);
}

What do you think about that?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no need for the condition type.
For using conditions in join you can use only WITH. If you try use ON you get the error:

An exception has been thrown during the rendering of a template ("[Syntax Error] line 0, col 137: Error: Expected Doctrine\ORM\Query\Lexer::T_WITH, got 'ON'").

See this doctrine/orm#7193 issue for more detales.

@Nyholm
Copy link
Member

Nyholm commented Aug 26, 2015

Thank you for this PR. This sure is a missing features. I just hade some minor comments.

if (!$this->conditionType) {
return DoctrineJoin::WITH;
}
if (!in_array($this->conditionType, [DoctrineJoin::ON, DoctrineJoin::WITH])) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should define our own ON and WITH constants. We don't want to be dependent on Doctrine.

@Nyholm
Copy link
Member

Nyholm commented Nov 9, 2015

Hey. I would really like to merge this? Any estimates when an update to this PR can be made?

@peter-gribanov
Copy link
Member

I consider this change to be unnecessary.
This is unnecessary over-complication.

This method mixes the level of business logic and persistence level.

The same result can be achieved easier:

Spec::andX(
    Spec::join('users', 'u'),
    Spec::eq('active', true, 'u'),
    Spec::eq('status', 'somestatus', 'u')
)

I prefer not to use the library directly, but i create specifications, the name of which describes the business rule:

Spec::andX(
    new JoinCommentUser('u'),
    new PublishedUser('u'),
    new UserWithStatus('somestatus', 'u')
)

@peter-gribanov
Copy link
Member

The new context system added in version 2 makes using relationships even easier.

Spec::andX(
    Spec::eq('active', true, 'users'),
    Spec::eq('status', 'somestatus', 'users')
)

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

Successfully merging this pull request may close these issues.

3 participants