PHP.GT

Overview

SqlBuilder has two main styles of use:

  1. define reusable query classes by extending one of the base query types
  2. build a query fluently with a builder object

Both styles produce SQL by implementing __toString(), so in everyday code they can be treated as strings when needed.

Query classes

Query classes are the core of the library.

For example, a SelectQuery subclass can define:

  • select()
  • from()
  • where()
  • groupBy()
  • having()
  • orderBy()
  • limit()
  • offset()

Each method returns the part of the SQL statement it is responsible for, and the parent class assembles the final query in the correct SQL order.

This is the style to prefer when:

  • the query is reused
  • one query naturally extends another
  • the query deserves its own name in the application
  • you want to test the query shape directly

Builders

Builders are the convenient, one-off version of the same idea.

Instead of subclassing a query type, we call fluent methods:

use GT\SqlBuilder\SelectBuilder;

$query = new SelectBuilder();
$query->select("id", "email")
	->from("user")
	->where("deletedAt is null")
	->orderBy("email");

Builders are useful when:

  • the query is local to one small piece of code
  • creating a dedicated class would add more noise than value
  • you want the same SQL shape as the class-based API, but inline

Fixed output order

One detail that often surprises people at first: builders do not output query parts in the order the methods were called. They output them in the normal SQL order for that query type.

That means this is still fine:

$query->having("count(*) > 1")
	->where("deletedAt is null")
	->groupBy("email");

The rendered SQL will still place where before group by, and group by before having to produce valid SQL syntax.

Each query part is stored once

Builder methods replace the whole part they refer to.

For example, calling:

$query->where("id = :id");
$query->where("enabled = true");

will leave only the second where clause in place. If you need more than one expression for a part, pass them together in one call:

$query->where(
	"id = :id",
	"enabled = true",
);

Conditions are first-class objects

Plain strings are allowed in where() and having(), but those clauses also support condition objects for grouping and comparison logic.

That means we can write code such as:

use GT\SqlBuilder\Condition\GreaterThan;
use GT\SqlBuilder\Condition\MultipleCondition;
use GT\SqlBuilder\Condition\MatchAny;

$query->where(
	"deletedAt is null",
	new MultipleCondition(
		new MatchAny(),
		new GreaterThan("score", 50),
		"status = 'priority'",
	),
);

We will cover those properly in Working with conditions.

Query execution is someone else’s job

SqlBuilder only builds SQL text. It does not bind parameters or talk to the database server.

That separation is useful because it lets this library stay small and predictable. If you need execution, pair it with your own database layer or with phpgt/database.

[!NOTE] In WebEngine applications, phpgt/database is the usual layer that executes queries. SqlBuilder or plain PHP files can be used to store queries, and WebEngine will load and execute the queries automatically.


Next, we will build a first working query in Getting started.