Spec-Zone.ru › Phalcon 2

Язык запросов Phalcon (PHQL)

Язык запросов Phalcon, PhalconQL или просто PHQL — это высокоуровневый, объектно-ориентированный диалект SQL, который позволяет писать запросы с использованием стандартизированного языка, похожего на SQL. PHQL реализован как парсер (написанный на C), который переводит синтаксис в синтаксис целевой СУБД.

Для достижения максимальной производительности Phalcon предоставляет парсер, использующий ту же технологию, что и SQLite. Эта технология обеспечивает небольшой парсер в памяти с очень низким потреблением памяти, который также потокобезопасен.

Парсер сначала проверяет синтаксис переданного заявления PHQL, затем строит промежуточное представление заявления и, наконец, преобразует его в соответствующий диалект SQL целевой СУБД.

В PHQL мы реализовали набор функций, чтобы сделать доступ к базам данных более безопасным:

  • Связанные параметры являются частью языка PHQL, помогая вам защитить ваш код
  • PHQL позволяет выполнять только одно SQL-заявление за вызов, предотвращая инъекции
  • PHQL игнорирует все SQL-комментарии, которые часто используются в SQL-инъекциях
  • PHQL допускает только операторы обработки данных, избегая случайного или внешнего изменения или удаления таблиц/баз данных без авторизации
  • PHQL реализует абстракцию высокого уровня, позволяющую обрабатывать таблицы как модели, а поля — как атрибуты класса

Пример использования

Для лучшего объяснения работы PHQL рассмотрим следующий пример. У нас есть две модели «Автомобили» и «Марки»:

class Cars extends Phalcon\Mvc\Model
{
    public $id;

    public $name;

    public $brand_id;

    public $price;

    public $year;

    public $style;

    /**
     * This model is mapped to the table sample_cars
     */
    public function getSource()
    {
        return 'sample_cars';
    }

    /**
     * A car only has a Brand, but a Brand have many Cars
     */
    public function initialize()
    {
        $this->belongsTo('brand_id', 'Brands', 'id');
    }
}

И каждый автомобиль принадлежит к определенной марке, поэтому у марки может быть много автомобилей:

class Brands extends Phalcon\Mvc\Model
{

    public $id;

    public $name;

    /**
     * The model Brands is mapped to the "sample_brands" table
     */
    public function getSource()
    {
        return 'sample_brands';
    }

    /**
     * A Brand can have many Cars
     */
    public function initialize()
    {
        $this->hasMany('id', 'Cars', 'brand_id');
    }
}

Создание запросов PHQL

Запросы PHQL можно создавать, просто создавая экземпляр класса Phalcon\Mvc\Model\Query:

// Instantiate the Query
$query = new Phalcon\Mvc\Model\Query("SELECT * FROM Cars", $this->getDI());

// Execute the query returning a result if any
$cars = $query->execute();

Из контроллера или представления легко создать/выполнить их с помощью введенного менеджера моделей:

//Executing a simple query
$query = $this->modelsManager->createQuery("SELECT * FROM Cars");
$cars = $query->execute();

//With bound parameters
$query = $this->modelsManager->createQuery("SELECT * FROM Cars WHERE name = :name:");
$cars = $query->execute(array(
    'name' => 'Audi'
));

Или просто выполнить его:

//Executing a simple query
$cars = $this->modelsManager->executeQuery("SELECT * FROM Cars");

//Executing with bound parameters
$cars = $this->modelsManager->executeQuery("SELECT * FROM Cars WHERE name = :name:", array(
    'name' => 'Audi'
));

Выбор записей

Как и в знакомом SQL, PHQL позволяет выполнять выбор записей с помощью оператора SELECT, который нам известен, за исключением того, что вместо указания таблиц мы используем классы моделей:

$query = $manager->createQuery("SELECT * FROM Cars ORDER BY Cars.name");
$query = $manager->createQuery("SELECT Cars.name FROM Cars ORDER BY Cars.name");

Также разрешены классы в именованных пространствах:

$phql = "SELECT * FROM Formula\Cars ORDER BY Formula\Cars.name";
$query = $manager->createQuery($phql);

$phql = "SELECT Formula\Cars.name FROM Formula\Cars ORDER BY Formula\Cars.name";
$query = $manager->createQuery($phql);

$phql = "SELECT c.name FROM Formula\Cars c ORDER BY c.name";
$query = $manager->createQuery($phql);

Большая часть стандарта SQL поддерживается PHQL, даже нестандартные директивы, такие как LIMIT:

$phql   = "SELECT c.name FROM Cars AS c "
   . "WHERE c.brand_id = 21 ORDER BY c.name LIMIT 100";
$query = $manager->createQuery($phql);

Типы результатов

В зависимости от типа столбцов, которые мы запрашиваем, тип результата будет разным. Если вы получаете один объект целиком, то возвращаемый объект — Phalcon\Mvc\Model\Resultset\Simple. Этот тип набора результатов представляет собой набор полных объектов модели:

$phql = "SELECT c.* FROM Cars AS c ORDER BY c.name";
$cars = $manager->executeQuery($phql);
foreach ($cars as $car) {
    echo "Name: ", $car->name, "\n";
}

Это точно так же, как:

$cars = Cars::find(array("order" => "name"));
foreach ($cars as $car) {
    echo "Name: ", $car->name, "\n";
}

Полные объекты могут быть изменены и сохранены обратно в базе данных, потому что они представляют полную запись связанной таблицы. Существуют и другие типы запросов, которые не возвращают полных объектов, например:

$phql = "SELECT c.id, c.name FROM Cars AS c ORDER BY c.name";
$cars = $manager->executeQuery($phql);
foreach ($cars as $car) {
    echo "Name: ", $car->name, "\n";
}

Мы запрашиваем только некоторые поля в таблице, поэтому их нельзя считать целым объектом, поэтому возвращаемый объект по-прежнему является набором результатов типа Phalcon\Mvc\Model\Resultset\Simple. Однако каждый элемент — это стандартный объект, содержащий только два запрошенных столбца.

Эти значения, которые не представляют полных объектов, мы называем скалярами. PHQL позволяет запрашивать все типы скаляров: поля, функции, литералы, выражения и т. д.:

$phql = "SELECT CONCAT(c.id, ' ', c.name) AS id_name FROM Cars AS c ORDER BY c.name";
$cars = $manager->executeQuery($phql);
foreach ($cars as $car) {
    echo $car->id_name, "\n";
}

Поскольку мы можем запрашивать полные объекты или скаляры, мы также можем запрашивать оба сразу:

$phql   = "SELECT c.price*0.16 AS taxes, c.* FROM Cars AS c ORDER BY c.name";
$result = $manager->executeQuery($phql);

В этом случае результатом является объект Phalcon\Mvc\Model\Resultset\Complex. Это позволяет одновременно получить доступ к полным объектам и скалярам:

foreach ($result as $row) {
    echo "Name: ", $row->cars->name, "\n";
    echo "Price: ", $row->cars->price, "\n";
    echo "Taxes: ", $row->taxes, "\n";
}

Скаляры отображаются как свойства каждой «строки», а полные объекты — как свойства с именем соответствующей модели.

Соединения

Легко запрашивать записи из нескольких моделей с помощью PHQL. Поддерживаются большинство типов соединений. Поскольку мы определили отношения в моделях, PHQL автоматически добавляет эти условия:

$phql  = "SELECT Cars.name AS car_name, Brands.name AS brand_name FROM Cars JOIN Brands";
$rows = $manager->executeQuery($phql);
foreach ($rows as $row) {
    echo $row->car_name, "\n";
    echo $row->brand_name, "\n";
}

По умолчанию предполагается внутреннее соединение. Вы можете указать тип соединения в запросе:

$phql = "SELECT Cars.*, Brands.* FROM Cars INNER JOIN Brands";
$rows = $manager->executeQuery($phql);

$phql = "SELECT Cars.*, Brands.* FROM Cars LEFT JOIN Brands";
$rows = $manager->executeQuery($phql);

$phql = "SELECT Cars.*, Brands.* FROM Cars LEFT OUTER JOIN Brands";
$rows = $manager->executeQuery($phql);

$phql = "SELECT Cars.*, Brands.* FROM Cars CROSS JOIN Brands";
$rows = $manager->executeQuery($phql);

Также возможно вручную задать условия соединения:

$phql = "SELECT Cars.*, Brands.* FROM Cars INNER JOIN Brands ON Brands.id = Cars.brands_id";
$rows = $manager->executeQuery($phql);

Также соединения могут быть созданы с использованием нескольких таблиц в операторе FROM:

$phql = "SELECT Cars.*, Brands.* FROM Cars, Brands WHERE Brands.id = Cars.brands_id";
$rows = $manager->executeQuery($phql);
foreach ($rows as $row) {
    echo "Car: ", $row->cars->name, "\n";
    echo "Brand: ", $row->brands->name, "\n";
}

Если используется псевдоним для переименования моделей в запросе, эти псевдонимы будут использоваться для именования атрибутов в каждой строке результата:

$phql = "SELECT c.*, b.* FROM Cars c, Brands b WHERE b.id = c.brands_id";
$rows = $manager->executeQuery($phql);
foreach ($rows as $row) {
    echo "Car: ", $row->c->name, "\n";
    echo "Brand: ", $row->b->name, "\n";
}

Когда связанная модель имеет отношение «многие ко многим» к модели «из», промежуточная модель неявно добавляется в сгенерированный запрос:

$phql = 'SELECT Brands.name, Songs.name FROM Artists ' .
        'JOIN Songs WHERE Artists.genre = "Trip-Hop"';
$result = $this->modelsManager->query($phql);

Этот код генерирует следующий SQL в MySQL:

SELECT `brands`.`name`, `songs`.`name` FROM `artists`
INNER JOIN `albums` ON `albums`.`artists_id` = `artists`.`id`
INNER JOIN `songs` ON `albums`.`songs_id` = `songs`.`id`
WHERE `artists`.`genre` = 'Trip-Hop'

Агрегации

Следующие примеры демонстрируют, как использовать агрегации в PHQL:

// How much are the prices of all the cars?
$phql = "SELECT SUM(price) AS summatory FROM Cars";
$row  = $manager->executeQuery($phql)->getFirst();
echo $row['summatory'];

// How many cars are by each brand?
$phql = "SELECT Cars.brand_id, COUNT(*) FROM Cars GROUP BY Cars.brand_id";
$rows = $manager->executeQuery($phql);
foreach ($rows as $row) {
    echo $row->brand_id, ' ', $row["1"], "\n";
}

// How many cars are by each brand?
$phql = "SELECT Brands.name, COUNT(*) FROM Cars JOIN Brands GROUP BY 1";
$rows = $manager->executeQuery($phql);
foreach ($rows as $row) {
    echo $row->name, ' ', $row["1"], "\n";
}

$phql = "SELECT MAX(price) AS maximum, MIN(price) AS minimum FROM Cars";
$rows = $manager->executeQuery($phql);
foreach ($rows as $row) {
    echo $row["maximum"], ' ', $row["minimum"], "\n";
}

// Count distinct used brands
$phql = "SELECT COUNT(DISTINCT brand_id) AS brandId FROM Cars";
$rows = $manager->executeQuery($phql);
foreach ($rows as $row) {
    echo $row->brandId, "\n";
}

Условия

Условия позволяют нам фильтровать набор записей, которые мы хотим запросить. Оператор WHERE позволяет это сделать:

// Simple conditions
$phql = "SELECT * FROM Cars WHERE Cars.name = 'Lamborghini Espada'";
$cars = $manager->executeQuery($phql);

$phql = "SELECT * FROM Cars WHERE Cars.price > 10000";
$cars = $manager->executeQuery($phql);

$phql = "SELECT * FROM Cars WHERE TRIM(Cars.name) = 'Audi R8'";
$cars = $manager->executeQuery($phql);

$phql = "SELECT * FROM Cars WHERE Cars.name LIKE 'Ferrari%'";
$cars = $manager->executeQuery($phql);

$phql = "SELECT * FROM Cars WHERE Cars.name NOT LIKE 'Ferrari%'";
$cars = $manager->executeQuery($phql);

$phql = "SELECT * FROM Cars WHERE Cars.price IS NULL";
$cars = $manager->executeQuery($phql);

$phql = "SELECT * FROM Cars WHERE Cars.id IN (120, 121, 122)";
$cars = $manager->executeQuery($phql);

$phql = "SELECT * FROM Cars WHERE Cars.id NOT IN (430, 431)";
$cars = $manager->executeQuery($phql);

$phql = "SELECT * FROM Cars WHERE Cars.id BETWEEN 1 AND 100";
$cars = $manager->executeQuery($phql);

Также в качестве части PHQL подготовленные параметры автоматически экранируют входные данные, повышая безопасность:

$phql = "SELECT * FROM Cars WHERE Cars.name = :name:";
$cars = $manager->executeQuery($phql, array("name" => 'Lamborghini Espada'));

$phql = "SELECT * FROM Cars WHERE Cars.name = ?0";
$cars = $manager->executeQuery($phql, array(0 => 'Lamborghini Espada'));

Вставка данных

С помощью PHQL можно вставлять данные с помощью знакомого оператора INSERT:

// Inserting without columns
$phql = "INSERT INTO Cars VALUES (NULL, 'Lamborghini Espada', "
      . "7, 10000.00, 1969, 'Grand Tourer')";
$manager->executeQuery($phql);

// Specifying columns to insert
$phql = "INSERT INTO Cars (name, brand_id, year, style) "
      . "VALUES ('Lamborghini Espada', 7, 1969, 'Grand Tourer')";
$manager->executeQuery($phql);

// Inserting using placeholders
$phql = "INSERT INTO Cars (name, brand_id, year, style) "
      . "VALUES (:name:, :brand_id:, :year:, :style)";
$manager->executeQuery($sql,
    array(
        'name'     => 'Lamborghini Espada',
        'brand_id' => 7,
        'year'     => 1969,
        'style'    => 'Grand Tourer',
    )
);

Phalcon не просто преобразует заявления PHQL в SQL. Все события и правила бизнеса, определенные в модели, выполняются так, как если бы мы создавали отдельные объекты вручную. Добавьте правило бизнеса в модели автомобилей. Стоимость автомобиля не может быть меньше 10 000 долларов:

use Phalcon\Mvc\Model\Message;

class Cars extends Phalcon\Mvc\Model
{

    public function beforeCreate()
    {
        if ($this->price < 10000)
        {
            $this->appendMessage(new Message("A car cannot cost less than $ 10,000"));
            return false;
        }
    }

}

Если мы выполним следующую вставку в модели автомобилей, операция не будет успешной, потому что цена не соответствует нашему правилу бизнеса:

$phql   = "INSERT INTO Cars VALUES (NULL, 'Nissan Versa', 7, 9999.00, 2012, 'Sedan')";
$result = $manager->executeQuery($phql);
if ($result->success() == false)
{
    foreach ($result->getMessages() as $message)
    {
        echo $message->getMessage();
    }
}

Обновление данных

Обновление строк очень похоже на вставку строк. Как вам известно, инструкция по обновлению записей — UPDATE. При обновлении записи выполняются события, связанные с операцией обновления, для каждой строки.

// Updating a single column
$phql = "UPDATE Cars SET price = 15000.00 WHERE id = 101";
$manager->executeQuery($phql);

// Updating multiples columns
$phql = "UPDATE Cars SET price = 15000.00, type = 'Sedan' WHERE id = 101";
$manager->executeQuery($phql);

// Updating multiples rows
$phql = "UPDATE Cars SET price = 7000.00, type = 'Sedan' WHERE brands_id > 5";
$manager->executeQuery($phql);

// Using placeholders
$phql = "UPDATE Cars SET price = ?0, type = ?1 WHERE brands_id > ?2";
$manager->executeQuery($phql, array(
    0 => 7000.00,
    1 => 'Sedan',
    2 => 5
));

Оператор UPDATE выполняет обновление в двух фазах:

  • Во-первых, если у UPDATE есть условие WHERE, он извлекает все объекты, соответствующие этим критериям,
  • Во-вторых, основываясь на запрошенных объектах, он обновляет/изменяет запрошенные атрибуты, сохраняя их в реляционной базе данных

Такой способ работы позволяет событиям, виртуальным внешним ключам и проверкам участвовать в процессе обновления. Вкратце, следующий код:

$phql = "UPDATE Cars SET price = 15000.00 WHERE id > 101";
$success = $manager->executeQuery($phql);

в некоторой степени эквивалентен:

$messages = null;

$process = function() use (&$messages) {
    foreach (Cars::find("id > 101") as $car) {
        $car->price = 15000;
        if ($car->save() == false) {
            $messages = $car->getMessages();
            return false;
        }
    }
    return true;
};

$success = $process();

Удаление данных

При удалении записи выполняются события, связанные с операцией удаления, для каждой строки:

// Deleting a single row
$phql = "DELETE FROM Cars WHERE id = 101";
$manager->executeQuery($phql);

// Deleting multiple rows
$phql = "DELETE FROM Cars WHERE id > 100";
$manager->executeQuery($phql);

// Using placeholders
$phql = "DELETE FROM Cars WHERE id BETWEEN :initial: AND :final:";
$manager->executeQuery(
    $phql,
    array(
        'initial' => 1,
        'final' => 100
    )
);

Операции DELETE также выполняются в двух фазах, как и UPDATE.

Создание запросов с помощью конструктора запросов

Доступен конструктор для создания запросов PHQL без необходимости писать заявления PHQL, а также для предоставления возможностей IDE:

//Getting a whole set
$robots = $this->modelsManager->createBuilder()
    ->from('Robots')
    ->join('RobotsParts')
    ->orderBy('Robots.name')
    ->getQuery()
    ->execute();

//Getting the first row
$robots = $this->modelsManager->createBuilder()
    ->from('Robots')
    ->join('RobotsParts')
    ->orderBy('Robots.name')
    ->getQuery()
    ->getSingleResult();

Это то же самое, что и:

$phql = "SELECT Robots.*
    FROM Robots JOIN RobotsParts p
    ORDER BY Robots.name LIMIT 20";
$result = $manager->executeQuery($phql);

Дополнительные примеры использования конструктора:

// 'SELECT Robots.* FROM Robots';
$builder->from('Robots');

// 'SELECT Robots.*, RobotsParts.* FROM Robots, RobotsParts';
$builder->from(array('Robots', 'RobotsParts'));

// 'SELECT * FROM Robots';
$phql = $builder->columns('*')
                ->from('Robots');

// 'SELECT id FROM Robots';
$builder->columns('id')
        ->from('Robots');

// 'SELECT id, name FROM Robots';
$builder->columns(array('id', 'name'))
        ->from('Robots');

// 'SELECT Robots.* FROM Robots WHERE Robots.name = "Voltron"';
$builder->from('Robots')
        ->where('Robots.name = "Voltron"');

// 'SELECT Robots.* FROM Robots WHERE Robots.id = 100';
$builder->from('Robots')
        ->where(100);

// 'SELECT Robots.* FROM Robots WHERE Robots.type = "virtual" AND Robots.id > 50';
$builder->from('Robots')
        ->where('type = "virtual"')
        ->andWhere('id > 50');

// 'SELECT Robots.* FROM Robots WHERE Robots.type = "virtual" OR Robots.id > 50';
$builder->from('Robots')
        ->where('type = "virtual"')
        ->orWhere('id > 50');

// 'SELECT Robots.* FROM Robots GROUP BY Robots.name';
$builder->from('Robots')
        ->groupBy('Robots.name');

// 'SELECT Robots.* FROM Robots GROUP BY Robots.name, Robots.id';
$builder->from('Robots')
        ->groupBy(array('Robots.name', 'Robots.id'));

// 'SELECT Robots.name, SUM(Robots.price) FROM Robots GROUP BY Robots.name';
$builder->columns(array('Robots.name', 'SUM(Robots.price)'))
    ->from('Robots')
    ->groupBy('Robots.name');

// 'SELECT Robots.name, SUM(Robots.price) FROM Robots GROUP BY Robots.name HAVING SUM(Robots.price) > 1000';
$builder->columns(array('Robots.name', 'SUM(Robots.price)'))
    ->from('Robots')
    ->groupBy('Robots.name')
    ->having('SUM(Robots.price) > 1000');

// 'SELECT Robots.* FROM Robots JOIN RobotsParts';
$builder->from('Robots')
    ->join('RobotsParts');

// 'SELECT Robots.* FROM Robots JOIN RobotsParts AS p';
$builder->from('Robots')
    ->join('RobotsParts', null, 'p');

// 'SELECT Robots.* FROM Robots JOIN RobotsParts ON Robots.id = RobotsParts.robots_id AS p';
$builder->from('Robots')
    ->join('RobotsParts', 'Robots.id = RobotsParts.robots_id', 'p');

// 'SELECT Robots.* FROM Robots ;
// JOIN RobotsParts ON Robots.id = RobotsParts.robots_id AS p ;
// JOIN Parts ON Parts.id = RobotsParts.parts_id AS t';
$builder->from('Robots')
    ->join('RobotsParts', 'Robots.id = RobotsParts.robots_id', 'p')
    ->join('Parts', 'Parts.id = RobotsParts.parts_id', 't');

// 'SELECT r.* FROM Robots AS r';
$builder->addFrom('Robots', 'r');

// 'SELECT Robots.*, p.* FROM Robots, Parts AS p';
$builder->from('Robots')
    ->addFrom('Parts', 'p');

// 'SELECT r.*, p.* FROM Robots AS r, Parts AS p';
$builder->from(array('r' => 'Robots'))
        ->addFrom('Parts', 'p');

// 'SELECT r.*, p.* FROM Robots AS r, Parts AS p';
$builder->from(array('r' => 'Robots', 'p' => 'Parts'));

// 'SELECT Robots.* FROM Robots LIMIT 10';
$builder->from('Robots')
    ->limit(10);

// 'SELECT Robots.* FROM Robots LIMIT 10 OFFSET 5';
$builder->from('Robots')
        ->limit(10, 5);

// 'SELECT Robots.* FROM Robots WHERE id BETWEEN 1 AND 100';
$builder->from('Robots')
        ->betweenWhere('id', 1, 100);

// 'SELECT Robots.* FROM Robots WHERE id IN (1, 2, 3)';
$builder->from('Robots')
        ->inWhere('id', array(1, 2, 3));

// 'SELECT Robots.* FROM Robots WHERE id NOT IN (1, 2, 3)';
$builder->from('Robots')
        ->notInWhere('id', array(1, 2, 3));

// 'SELECT Robots.* FROM Robots WHERE name LIKE '%Art%';
$builder->from('Robots')
        ->where('name LIKE :name:', array('name' => '%' . $name . '%'));

// 'SELECT r.* FROM Store\Robots WHERE r.name LIKE '%Art%';
$builder->from(['r' => 'Store\Robots'])
        ->where('r.name LIKE :name:', array('name' => '%' . $name . '%'));

Связанные параметры

Связанные параметры в конструкторе запросов можно задавать по мере построения запроса или передавать их все сразу при выполнении:

//Passing parameters in the query construction
$robots = $this->modelsManager->createBuilder()
    ->from('Robots')
    ->where('name = :name:', array('name' => $name))
    ->andWhere('type = :type:', array('type' => $type))
    ->getQuery()
    ->execute();

//Passing parameters in query execution
$robots = $this->modelsManager->createBuilder()
    ->from('Robots')
    ->where('name = :name:')
    ->andWhere('type = :type:')
    ->getQuery()
    ->execute(array('name' => $name, 'type' => $type));

Отключение литералов в PHQL

Литералы могут быть отключены в PHQL, что означает, что прямое использование строк, чисел и логических значений в строках PHQL будет запрещено. Если заявления PHQL создаются путем встраивания внешних данных в них, это может открыть приложение для потенциальных SQL-инъекций:

$login = 'voltron';
$phql = "SELECT * FROM Models\Users WHERE login = '$login'";
$result = $manager->executeQuery($phql);

Если $login изменится на ‘ OR ‘’ = ‘, сгенерированное PHQL будет:

"SELECT * FROM Models\Users WHERE login = '' OR '' = ''"

Что всегда истинно, независимо от того, что хранится в базе данных как значение login.

Если литералы запрещены, строки могут использоваться в качестве части заявления PHQL, при этом будет выброшено исключение, заставляя разработчика использовать связанные параметры. Тот же запрос можно записать безопасным способом так:

$phql = "SELECT Robots.* FROM Robots WHERE Robots.name = :name:";
$result = $manager->executeQuery($phql, array('name' => $name));

Отключить литералы можно следующим образом:

Phalcon\Mvc\Model::setup(array('phqlLiterals' => false));

Связанные параметры можно использовать даже если литералы разрешены или нет. Отключение их — просто еще одно решение по обеспечению безопасности, которое разработчики могут принять в веб-приложениях.

Экранирование зарезервированных слов

В PHQL есть несколько зарезервированных слов. Если вы хотите использовать любое из них в качестве имен атрибутов или моделей, вам необходимо экранировать эти слова с помощью разделителей экранирования «[» и «]»:

$phql = "SELECT * FROM [Update]";
$result = $manager->executeQuery($phql);

$phql = "SELECT id, [Like] FROM Posts";
$result = $manager->executeQuery($phql);

Разделители динамически переводятся в допустимые разделители в зависимости от системы баз данных, на которой в данный момент работает приложение.

Жизненный цикл PHQL

Как высокоуровневый язык, PHQL предоставляет разработчикам возможность персонализировать и настраивать различные аспекты в соответствии со своими потребностями. Следующий — жизненный цикл каждого выполненного заявления PHQL:

  • PHQL парсится и преобразуется в промежуточное представление (IR), которое не зависит от реализованного SQL системой баз данных
  • IR преобразуется в допустимый SQL в соответствии с системой баз данных, связанной с моделью
  • Заявления PHQL парсятся один раз и кешируются в памяти. Дальнейшее выполнение того же заявления приводит к несколько более быстрому выполнению

Использование простого SQL

Система баз данных может предлагать определенные расширения SQL, которые не поддерживаются PHQL. В этом случае может быть уместен простой SQL:

use Phalcon\Mvc\Model\Resultset\Simple as Resultset;

class Robots extends Phalcon\Mvc\Model
{
    public static function findByCreateInterval()
    {
        // A raw SQL statement
        $sql = "SELECT * FROM robots WHERE id > 0";

        // Base model
        $robot = new Robots();

        // Execute the query
        return new Resultset(null, $robot, $robot->getReadConnection()->query($sql));
    }
}

Если запросы с простым SQL распространены в вашем приложении, в вашу модель можно добавить универсальный метод:

use Phalcon\Mvc\Model\Resultset\Simple as Resultset;

class Robots extends Phalcon\Mvc\Model
{
    public static function findByRawSql($conditions, $params=null)
    {
        // A raw SQL statement
        $sql = "SELECT * FROM robots WHERE $conditions";

        // Base model
        $robot = new Robots();

        // Execute the query
        return new Resultset(null, $robot, $robot->getReadConnection()->query($sql, $params));
    }
}

Вышеупомянутый findByRawSql можно использовать следующим образом:

$robots = Robots::findByRawSql('id > ?', array(10));

Устранение неполадок

Некоторые моменты, которые следует учитывать при использовании PHQL:

  • Классы чувствительны к регистру. Если класс не определен с тем же именем, что и при его создании, это может привести к непредсказуемому поведению в операционных системах с регистрозависимой файловой системой, таких как Linux.
  • Необходимо правильно определить кодировку в подключении, чтобы успешно привязать параметры.
  • Псевдонимы классов не заменяются полными именами пространств имен, поскольку это происходит только в коде PHP, а не внутри строк.
  • Если включено переименование столбцов, избегайте использования псевдонимов столбцов с теми же именами, что и столбцы, которые нужно переименовать. Это может привести к путанице в резольвере запросов.

© 2011–2016 Phalcon Framework Team
Licensed under the Creative Commons Attribution License 3.0.
https://docs.phalconphp.com/en/2.0.0/reference/phql.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API