These classes serve as a wrapper for Node
instances implementing ScalarExpression
interface, that should
(presumably) return boolean values when used in SQL.
Condition
instances are used by fragments that modify WHERE
and HAVING
clauses and by the JoinFragment
for an actual JOIN
condition.
Conditions behave like Specifications from the pattern of the same name and can be combined via AND
/ OR
/ NOT
operators. They do not implement isSatisfiedBy()
method, though, for more or less obvious reasons.
This abstract class implements KeyEquatable
and FragmentBuilder
interfaces. The latter allows passing instances of
Condition
to query methods of TableGateway
, appending them to the query's WHERE
clause.
It also defines the abstract generateExpressionImpl(): ScalarExpression
method that should be implemented in
child classes and a generateExpression(): ScalarExpression
wrapper around it which clones the result
of generateExpressionImpl()
. This is done to prevent potential problems when reusing the same expression in multiple
queries / multiple parts of the query, as pg_builder
's Node
classes keep a reference to their parent Node
.
Method name starts with "generate" as a hint: it should preferably generate the ScalarExpression
on "as needed"
basis rather than pre-generate and store that. Real world Condition
s will use Parser
and parsing may be slow.
The Condition
class has static methods for combining the conditions using logical operators:
and(self ...$children): AndCondition
- creates aCondition
that combines several otherCondition
s usingAND
operator.or(self ...$children): OrCondition
- creates aCondition
that combines several otherCondition
s usingOR
operator.not(self $child): NotCondition
- creates a negatedCondition
.
For example:
$combined = Condition::and(
Condition::not($firstCondition),
Condition::or($secondCondition, $thirdCondition)
);
Classes returned by the above methods can also be instantiated explicitly.
Constructor of AndCondition
/ OrCondition
accepts variable number of Condition
parameters
__construct(Condition ...$children)
and will throw an InvalidArgumentException
if none are given.
Constructor of NotCondition
naturally accepts only one Condition
argument.
Using the above example with explicit classes:
$combined = new AndCondition(
new NotCondition($firstCondition),
new OrCondition($secondCondition, $thirdCondition)
);
All these classes implement Parametrized
interface and will propagate parameters from their child Condition
s.
While it is possible to also implement Parametrized
in custom conditions, the suggested approach is to use
ParametrizedCondition
decorator instead.
Its constructor accepts an instance of Condition
and an array with parameter values
__construct(Condition $wrapped, array<string, mixed> $parameters)
and will throw an InvalidArgumentException
if $wrapped
already implements Parametrized
.
$condition = new ParametrizedCondition(
new SqlStringCondition($parser, 'foo = :bar::baz'),
['bar' => new Baz()]
);
It is rarely needed to manually create these classes as they are all supported by
custom builder classes and
builder methods of FluentBuilder
.
Generates a self.foo = any(:foo::foo_type[])
condition for the foo
table column. This is similar to foo IN (...)
,
but requires only one placeholder.
Constructor accepts a Column
instance and an implementation of TypeNameNodeHandler
:
$condition = new AnyCondition(
$gateway->getColumns()->get('foo'),
$locator->getTypeConverterFactory()
);
Uses the value of the bool-typed column as a Condition
. Constructor accepts an instance of Column
, will throw
LogicException
if it is not of type bool.
$condition = new BoolCondition($gateway->getColumns()->get('flag'));
Generates the EXISTS(SELECT ...)
condition using the given SelectProxy
. The constructor may also accept
a join Condition
and an explicit alias for a table within EXISTS(...)
(will be autogenerated if not given):
__construct(SelectProxy $select, ?Condition $joinCondition = null, ?string $explicitAlias = null)
$condition = new ExistsCondition(
$gateway->select(/* ... some configuration ... */),
new ForeignKeyCondition($foreignKey),
'custom'
);
Generates a join condition using the given foreign key constraint. Constructor accepts a ForeignKey
object
and a flag specifying whether we are joining from the side of the child table (one having the constraint defined)
or the parent one (referenced by constraint). self
and joined
aliases will be used according to that flag.
// This will use 'self' alias for referenced table and 'joined' alias for child one
$condition = new ForeignKeyCondition($foreignKey, false);
Generates a self.foo IS NULL
Condition for the foo
table column. Constructor accepts an instance of Column
.
$condition = new IsNullCondition($gateway->getColumns()->get('foo'));
Generates a self.foo <> all(:foo::foo_type[])
condition for the foo
table column.
This is similar to foo NOT IN (...)
, but requires only one placeholder.
Constructor accepts a Column
instance and an implementation of TypeNameNodeHandler
:
$condition = new NotAllCondition(
$gateway->getColumns()->get('foo'),
$locator->getTypeConverterFactory()
);
Generates a self.foo OPERATOR :foo::foo_type
condition for the foo
table column. Constructor accepts an instance
of Column
, an implementation of TypeNameNodeHandler
and operator as string:
$condition = new OperatorCondition(
$gateway->getColumns()->get('foo'),
$locator->getTypeConverterFactory(),
'>='
);
A condition for finding a table row by its primary key. Constructor accepts a PrimaryKey
object and
an implementation of TypeNameNodeHandler
:
$condition = new PrimaryKeyCondition(
$gateway->getPrimaryKey(),
$locator->getTypeConverterFactory()
);
This class also has an additional normalizeValue(mixed $value): array<string, mixed>
which accepts the value
probably passed to one of the methods of PrimaryKeyAccess
interface and ensures that it can be used in parameter
values for the query. E.g.
$condition->normalizeValue(1);
will return a ['id' => 1]
array if table's primary key consists of single id
column and
$condition->normalizeValue(['foo_id' => 2]);
will throw an Exception if table's primary key consists of foo_id
and bar_id
columns.
Condition represented by an SQL string. Constructor accepts a Parser
instance and a string.
$condition = new SqlStringCondition(
$parser,
"current_date between coalesce(self.valid_from, 'yesterday') and coalesce(self.valid_to, 'tomorrow')"
);
Note that the string will eventually be processed by parseExpression()
method and added to query AST,
so self
aliases in it will be replaced if needed and parameter placeholders will be processed.