Welcome Guest, Not a member yet? Register   Sign In
Change in SQLSRV builder database name prefixes from v4.1 to v4.4
#5

(12-11-2023, 05:11 PM)kenjis Wrote: That is a bug fix, and your usage does not seem to be assumed. 
So it seems better to extend the DB classes.
See https://forum.codeigniter.com/thread-782...83813.html

Thanks, between the two posts I was able to solve the issue.

Sadly, the way we do alternate databases doesn't work (the double periods was causing issues), so I just ended up replacing the join function with the basebuilder one.

In case someone wants to avoid the guessing game... here is what I did:

Created class files in App/Database/Mydriver for Connection, Builder, Forge, PreparedQuery, Result and Utils

The Connection.php file:
Code:
<?php

namespace App\Database\Mydriver;

class Connection extends \CodeIgniter\Database\SQLSRV\Connection
{
    /**
    * Class constructor
    *
    * @param  array $params
    * @return void
    */
    public function __construct($params)
    {
        // Create the class aliases
        self::aliasClasses();

        parent::__construct($params);

        // This is only supported as of SQLSRV 3.0
        if ($this->scrollable === null)
        {
            $this->scrollable = defined('SQLSRV_CURSOR_CLIENT_BUFFERED') ? SQLSRV_CURSOR_CLIENT_BUFFERED : false;
        }

    }

    /**
    * Aliases the companion classes to the driver.
    */
    private static function aliasClasses()
    {
        foreach (['Builder', 'Forge', 'PreparedQuery', 'Result', 'Utils'] as $name)
        {
            $original = 'CodeIgniter\Database\SQLSRV\\' . $name;
            $alias    = APPPATH.'Database\Mydriver\\' . $name;
            if (! class_exists($alias))
            {
                class_alias($original, $alias);
            }
        }
    }
}

The Builder.php file:
Code:
<?php
namespace App\Database\Mydriver;

class Builder extends \CodeIgniter\Database\SQLSRV\Builder
{
   
    /**
    * Generates the JOIN portion of the query
    *
    * @param RawSql|string $cond
    *
    * @return $this
    */
    public function join(string $table, $cond, string $type = '', ?bool $escape = null)
    {
        if ($type !== '') {
            $type = strtoupper(trim($type));

            if (! in_array($type, $this->joinTypes, true)) {
                $type = '';
            } else {
                $type .= ' ';
            }
        }

        // Extract any aliases that might exist. We use this information
        // in the protectIdentifiers to know whether to add a table prefix
        $this->trackAliases($table);

        if (! is_bool($escape)) {
            $escape = $this->db->protectIdentifiers;
        }

        // Do we want to escape the table name?
        if ($escape === true) {
            $table = $this->db->protectIdentifiers($table, true, null, false);
        }

        if ($cond instanceof RawSql) {
            $this->QBJoin[] = $type . 'JOIN ' . $table . ' ON ' . $cond;

            return $this;
        }

        if (! $this->hasOperator($cond)) {
            $cond = ' USING (' . ($escape ? $this->db->escapeIdentifiers($cond) : $cond) . ')';
        } elseif ($escape === false) {
            $cond = ' ON ' . $cond;
        } else {
            // Split multiple conditions
            if (preg_match_all('/\sAND\s|\sOR\s/i', $cond, $joints, PREG_OFFSET_CAPTURE)) {
                $conditions = [];
                $joints    = $joints[0];
                array_unshift($joints, ['', 0]);

                for ($i = count($joints) - 1, $pos = strlen($cond); $i >= 0; $i--) {
                    $joints[$i][1] += strlen($joints[$i][0]); // offset
                    $conditions[$i] = substr($cond, $joints[$i][1], $pos - $joints[$i][1]);
                    $pos            = $joints[$i][1] - strlen($joints[$i][0]);
                    $joints[$i]    = $joints[$i][0];
                }
                ksort($conditions);
            } else {
                $conditions = [$cond];
                $joints    = [''];
            }

            $cond = ' ON ';

            foreach ($conditions as $i => $condition) {
                $operator = $this->getOperator($condition);

                $cond .= $joints[$i];
                $cond .= preg_match('/(\(*)?([\[\]\w\.\'-]+)' . preg_quote($operator, '/') . '(.*)/i', $condition, $match) ? $match[1] . $this->db->protectIdentifiers($match[2]) . $operator . $this->db->protectIdentifiers($match[3]) : $condition;
            }
        }

        // Assemble the JOIN statement
        $this->QBJoin[] = $type . 'JOIN ' . $table . $cond;

        return $this;
    }
}

Then in the .ENV file:
Code:
database.default.DBDriver = 'App\Database\Mydriver'

or in the App/Config/Database.php file:
Code:
public array $default = [
'DSN'      => '',
'hostname' => 'localhost',
'username' => '',
'password' => '',
'database' => '',
'DBDriver' => 'App\Database\Mydriver',
...
];

All of the other class files look like this (each with their own name and extended from the correct class):
Code:
<?php

namespace App\Database\Mydriver;

class Forge extends \CodeIgniter\Database\SQLSRV\Forge
{

}

Also, in the Autoloader.php in the App/Config, I added this (although I don't think it is needed):
Code:
public $classmap = [
        'Builder' => APPATH.'Database\Mydrvier\Builder.php',
        'Forge' => APPATH.'Database\Mydrvier\Forge.php',
        'PreparedQuery' => APPATH.'Database\Mydrvier\PreparedQuery.php',
        'Result' => APPATH.'Database\Mydrvier\Result.php',
        'Utils' => APPATH.'Database\Mydrvier\Utils.php',
    ];

There is likely a more elegant way to solve this, but this got this part done so I could move on to the rest of the issues.
Reply


Messages In This Thread
RE: Change in SQLSRV builder database name prefixes from v4.1 to v4.4 - by Kaosweaver - 12-12-2023, 07:19 AM



Theme © iAndrew 2016 - Forum software by © MyBB