tra-loi-cau-hoi-phat-trien-web.com

JDatabase, mẫu câu lệnh SQL

Có cách nào để sử dụng mẫu câu lệnh, như của Hibernate HQL không?

SQLQuery sql=s.createSQLQuery("SELECT AVG(RATING) as r, COUNT(*) as c FROM RATINGS WHERE ADVENTURE_ID = ?");
sql.setParameter(0, adventureId);

Hoặc nếu chúng ta không nói về ORM, thì giống như PDO?

$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)");
$stmt->bindParam(':name', $name);
$stmt->bindParam(':value', $value);

Tôi thực sự không muốn nối chuỗi và trích dẫn dữ liệu được chèn thủ công, điều đó thật đáng thất vọng trong năm 2017.

$db = JFactory::getDbo();
$db->setQuery('SELECT params FROM #__extensions WHERE name = ' . $db->quote('com_democompupdate'));

hoặc thậm chí tệ hơn

$query->select($db->quoteName(array('user_id', 'profile_key', 'profile_value', 'ordering')));
$query->from($db->quoteName('#__user_profiles'));
$query->where($db->quoteName('profile_key') . ' LIKE '. $db->quote('\'custom.%\''));
$query->order('ordering ASC');

Tôi không thực sự cần ORM trong dự án này, db sẽ là MySQL mãi mãi, tôi chỉ cần một cách để có được kết nối, bắt đầu giao dịch và thực hiện các mẫu câu lệnh.

Lưu ý rằng tôi không muốn tạo kết nối PDO mới, tôi muốn làm điều này với kết nối JDatabase. Tôi không muốn thành phần biết bất cứ điều gì về tài khoản db.

2
inf3rno

Tôi thấy có một $query->bind phương thức, vì vậy có thể tạo một câu lệnh đã chuẩn bị, hoặc bất cứ điều gì chúng ta gọi nó. Nhưng trong trường hợp của tôi thì điều này không đơn giản. Tôi có phiên bản 3.4.3, tôi không phải là người duy trì trang web, vì vậy tôi không muốn thay đổi cấu hình hoặc chuyển sang phiên bản mới hơn. Tôi không muốn thử nghiệm trên máy chủ sản xuất và tôi không có môi trường phát triển cho PHP, chỉ có notepad. Điều này là do tôi chỉ làm việc trên một thành phần nhỏ và tôi không muốn mua IDE như PHPStorm chỉ để kết thúc dự án này trong tối đa 5 ngày. Tôi kiểm tra trong sản xuất quá. Tôi hiểu điều này là không hoàn hảo ...

Trong cấu hình tôi thấy rằng $dbtype = 'mysqli'. Afaik. mysqli hỗ trợ các câu lệnh đã chuẩn bị quá, nhưng điều đó không nhất thiết có nghĩa là trình điều khiển mysqli cũng hỗ trợ nó.

Vào đầu Joomla 3.x năm 2014, chỉ có SQLite và Oracle có trình điều khiển dựa trên PDO và các trình điều khiển khác không hỗ trợ các câu lệnh được chuẩn bị.

Tôi thấy rằng phiên bản Joomla của tôi là từ năm 2015 và tính năng này đã được thêm vào trình điều khiển mysqli vào năm 2016 . Tôi đã viết một lớp QueryTemplate đơn giản, tôi sẽ sử dụng nó như một cách giải quyết. Tôi thực sự khuyên mọi người khác nên chuyển sang phiên bản mới nếu có thể và không bao giờ kiểm tra mã của bạn trong môi trường sản xuất! : D: D: D

Tôi thấy rằng phiên bản của tôi hỗ trợ các giao dịch. Ít nhất là ổn. Tôi quyết định bọc lớp j Joomla, nhưng điều này không bắt buộc, bạn có thể sử dụng mẫu mà không cần điều đó.

JoomlaQueryTemplate.php :

namespace Canteen\infrastructure;

use Canteen\infrastructure\iTemplate;
use JFactory;
use Exception;

class JoomlaQueryTemplate implements iTemplate {

    public function __construct($template){
        if (!is_string($template))
            throw new Exception('Invalid SQL template.');
        $this->template = $template;
    }

    public function evaluate($data){
        return preg_replace_callback('/:(\w+)/usD', function ($match) use ($data) {
            $param = $match[1];
            if (!array_key_exists($param, $data))
                throw new Exception('Not given param: '.$param);
            $value = JFactory::getDbo()->quote($data[$param]);
            return $value;
        }, $this->template);
    }

}

JoomlaConnection.php

namespace Canteen\infrastructure;

use Canteen\infrastructure\JoomlaQueryTemplate;
use JFactory;

class JoomlaConnection implements iConnection {

    protected $connection;

    public function __construct(){
        $this->connection = JFactory::getDbo();
    }

    public function execute($template, $data = array()){
        $queryTemplate = new JoomlaQueryTemplate($template);
        $query = $queryTemplate->evaluate($data);
        $this->connection->setQuery($query);
        $this->connection->execute();
    }

    public function getId(){
        return $this->connection->insertid();
    }

    public function query($template, $data = array()){
        $queryTemplate = new JoomlaQueryTemplate($template);
        $query = $queryTemplate->evaluate($data);
        $this->connection->setQuery($query);
        $this->connection->execute();
    }

    public function isEmpty(){
        $rowsCount = $this->connection->getNumRows();
        return $rowsCount == 0;
    }

    public function getMany(){
        return $this->connection->loadObjectList();
    }

    public function getOne(){
        return $this->connection->loadObject();
    }

    public function getValues(){
        return $this->connection->loadColumn();
    }

    public function getValue(){
        return $this->connection->loadResult();
    }

    public function beginTransaction(){
        $this->connection->transactionStart();
    }

    public function commit(){
        $this->connection->transactionCommit();
    }

    public function rollback(){
        $this->connection->transactionRollback();
    }

}

Kết nối được đưa vào repos và dịch vụ ứng dụng của tôi. Vì vậy, các dịch vụ ứng dụng có thể xử lý các giao dịch và các repos có thể gửi truy vấn sql. Ví dụ:

public function readStatistics(){
    $statisticsDTO = new CustomerStatisticsDTO();
    try {
        $this->connection->beginTransaction();
        $statisticsDTO->setTotalCount($this->repository->countCustomers());
        $statisticsDTO->setActiveCount($this->repository->countActiveCustomers());
        $statisticsDTO->setSuspendedCount($this->repository->countSuspendedCustomers());
        $this->connection->commit();
    }
    catch (Exception $exception){
        $this->connection->rollback();
        throw $exception;
    }
    $statisticsDTO->setPassiveCount($statisticsDTO->getTotalCount() - $statisticsDTO->getActiveCount());
    $statisticsDTO->setOrderingCount($statisticsDTO->getActiveCount() - $statisticsDTO->getSuspendedCount());
    return $statisticsDTO;
}

public function countSuspendedCustomers(){
    $today = new DateTime('today');
    $this->connection->query(
        'SELECT COUNT(`#__canteen_customers`.`user_id`) AS `result` '.
        'FROM `#__canteen_customers` '.
        'WHERE '.
            '0 < ('.
                'SELECT count(`#__canteen_suspensions`.`suspension_id`) AS `active_suspension_count` '.
                'FROM `#__canteen_suspensions` '.
                'WHERE '.
                    '`#__canteen_customers`.`user_id` = `#__canteen_suspensions`.`user_id` AND '.
                    '`#__canteen_suspensions`.`suspension_from` <= :date AND '.
                    '(`#__canteen_suspensions`.`suspension_to` IS NULL OR `#__canteen_suspensions`.`suspension_to` >= :date)'.
            ') AND '.
            '`#__canteen_customers`.`customer_active` = TRUE',
        array(
            'date' => $today->format('Y-m-d')
        )
    );

    return (int) $this->connection->getValue();
}

(Tôi biết rằng tôi không phải quay ngược lại chỉ bằng các câu lệnh chọn, nhưng tôi chỉ sao chép phần mã đó và nó không gây hại gì. Tôi đoán sẽ tốt hơn với đơn vị công việc, nhưng tôi đang học mô hình đó sau.)

Tôi khá chắc chắn rằng api của trình xây dựng truy vấn j Joomla ban đầu cũng tốt, nhưng tôi cảm thấy tự nhiên hơn khi sử dụng các câu lệnh đã chuẩn bị, vì tôi không phải học cách dịch giữa mã trình tạo truy vấn và sql kết quả. Tôi không muốn sử dụng ví dụ như pssql sau này, vì vậy tôi có thể viết sql thay vì tạo nó. Tất nhiên nếu bạn có thể chọn, sau đó cài đặt phiên bản j Joomla mới nhất, hỗ trợ các câu lệnh được chuẩn bị và sử dụng nó thay vì cái này.

1
inf3rno