متد __construct در PDOQueryBuilder

پرسیده شده
فعالیت 947 روز پیش
دیده شده 502 بار
0

سلام و عرض ادب

استاد من بقیه تاپیک ها که در این مورد سوال کرده بودند رو هم خوندم، فقط موضوعی که متوجه نشدم اینه که اینجا با این دستور:

public function __construct(DatabaseConnectionInterface $connection)

ما یه آبجکت از کلاس DatabaseConnectionInterface ساختیم و درون متغیر connection قراردادیم. بعد متد getConnection کلاس DatabaseConnectionInterface رو به متغیر connectionی که درون QueryBuilder بود پاس دادیم. ولی متد getConnectionی که در کلاس DatabaseConnectionInterface هست که اصلا بدنه نداره و کلاس DatabaseConnectionInterface هم که اصلا کلاس PDO رو extend نکرده، پس چجوری متغیر connectionی که درون کلاس QueryBuilder قرار داشت تونست از متدهای کلاس PDO استفاده کنه؟

یعنی تونست این متدها رو از کلاس PDODatabaseConnection که فرزند DatabaseConnectionInterface هست، بگیره؟

فایل پیوست

2
حذف شده

ممنون بابت توضیحات واضحتون

اول اصلا بیایید خود تابع lastInsertId رو درک کنیم. این تابع رو میشه مستقیم از کلاس pdo صدا زد تا متوجه شد دقیقا آخرین رکوردی که ثبت شده چه آیدی داشته و از اون جایی که connection حاوی pdo ما هستش ما میتوینم این تابع رو صدا بزنیم

https://www.php.net/manual/en/pdo.lastinsertid.php

 

 

درون construct کلاس PDOQueryBuilder هم قطعا یک جا از این کلاس یک شی ساخته شده و آبجکتی از کلاس که از نوع DatabaseConnectionInterface هستش بهش داده شده.

 

داخل DatabaseConnectionInteface یک سری متد تعریف شده که همه connectionهایی که از این inteface میخوان ارث بری کنن باید همچین رفتارهایی رو داشته باشن

interface DatabaseConnectionInterface{
    public function connect();
    public function getConnection();
}

 و برای مثال PDODatabaseConnection که یم نوع connection هستش اومده این اینترفیس رو ارث بری کرده و متدها شو طبیعتا باید پیاده سازی کنه

 

به این دقت کنید که ما وقتی نوع ورودیمون رو به این شکل از نوع یک interface مشخص کردیم به این معنا نیست که خود inteface باید پاس داده بشه بلکه به این معناست که کلاس هایی که از این interface ارث بری کردن باید بهش پاس داده بشه

ما این interface رو داشتیم تا بتونیم connectionهای مختلفی داشته باشیم که رفتار شبیه به هم رو دارند (connection و getConnection). اگه هر کلاس connectionی مثل PDOConnection از این interface ارث بری کنند ما مطمئنیم که این دو تا متد رو داخل اون کلاس داریم چون پیاده سازی شده و اگه  تصمیم بگیریم connectionمون رو تغییر بدیم از PDO به Mysql میدونیم که کد ما break نمیشه و همون متدهای connect و getConnection رو داره که موارد داخل ویدیوهای SOLID گفته شده

 

اگر جایی ابهام داشتید بگید تا بیشتر توضیح بدم 

فایل پیوست

امیر صالحی

توسط

امیر صالحی

9 مهر 00

0
حذف شده

سلام و احترام

امکانش هست با کد توضیح بدید؟ یا anydesk بزنیم و دربارش صحبت کنیم

فایل پیوست

امیر صالحی

توسط

امیر صالحی

8 مهر 00

1
حذف شده

با تشکر آقای صالحی، ببینید:

interface DatabaseConnectionInterface{
    public function connect();
    public function getConnection();
}

اینجا اینترفیس DatabaseConnectionInterface رو داریم.

 

در ادامه:

class PDODatabaseConnection implements DatabaseConnectionInterface
{
    protected $connection;
    protected $config;
    const REQURED_CONFIG_KEYS = [
        'driver',
        'host',
        'database',
        'dbuser',
        'dbpassword'
    ];
    public function __construct(array $config)
    {
        if (!$this->isConfigValid($config)) {
            throw new ConfigNotValidException;
        }
        $this->config = $config;
    }
    public function connect()
    {
        $dsn = $this->generateDsn($this->config);

        try {
            $this->connection = new PDO(...$dsn);
            $this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            $this->connection->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
        } catch (PDOException $e) {
            throw new DatabaseConnectionException($e->getMessage());
        }
        return $this;
    }
    public function getConnection()
    {
        return $this->connection;
    }

    private function generateDsn(array $config)
    {
        $dsn = "{$config['driver']}:host={$config['host']};dbname={$config['database']}";
        return [$dsn, $config['dbuser'], $config['dbpassword']];
    }
    private function isConfigValid(array $config)
    {
        $matches = array_intersect(self::REQURED_CONFIG_KEYS, array_keys($config));
        return count($matches) === count(self::REQURED_CONFIG_KEYS);
    }
}

کلاس PDODatabaseConnection رو داریم که اینترفیس DatabaseConnectionInterface  رو ایمپلیمنت کرده. و همچنین میبینیم که در متد ()connect این کلاس، یه ابجکت از کلاس PDO ساخته شده و متد getConnection هم این آبجکت رو برمیگردونه.

 

در ادامه:

class PDOQueryBuilder
{
    protected $connection;
   
    public function __construct(DatabaseConnectionInterface $connection)
    {
        $this->connection = $connection->getConnection();
    }
        public function create(array $data)
    {
        $placeholder = [];
        foreach ($data as $column => $value) {
            $placeholder[] = '?';
        }
        $fields = implode(',', array_keys($data));
        $placeholder = implode(',', $placeholder);
        $this->values = array_values($data);
        $sql = "INSERT INTO {$this->table} ({$fields}) VALUES ({$placeholder})";
        $this->execute($sql);
        return (int)$this->connection->lastInsertId();
    }

کلاس PDOQueryBuilder رو داریم که تو متد construct اومده یه آبجکت به نام connection$ از اینترفیس DatabaseConnectionInterface ساخته و متد ()getConnection اون آبجکت رو درون پراپرتی connection$ کلاس PDOQueryBuilder قرار داده. و در ادامه اومده به طور مثال درون متد create از پراپرتی connection استفاده کرده و متد lastInsertId رو برگردونده.(و این رو میدونیم که این متد از کلاس PDO گرفته میشه.)

 

حالا سوال من اینه که متد getConnection، درون اینترفیس DatabaseConnectionInterface اصلا بدنه نداره. و هیچ کاری انجام نمیده، صرفا یه قرارداده که هر کلاسی که ایمپلیمنتش کرد باید از این متد استفاده کنه. و در ضمن اینترفیس DatabaseConnectionInterface هم که کلاس PDO رو extend نکرده که بتونه متد lastInsertId  رو ازش به ارث ببره.

پس آبجکت connection$ که درون متد construct کلاس PDOQueryBuilder  از اینترفیس DatabaseConnectionInterface ساخته شده هم نمیتونه متد lastInsertId رو داشته باشه. پس نمیتونه این متد رو به پراپرتی connection$ کلاس PDOQueryBuilder  بده.

 

پس چجوری پراپرتی connection در خط آخر متد create تونسته از متد lastInsertId استفاده کنه و اون رو برگردونه؟

 

آیا دلیلش اینه که کلاس PDODatabaseConnection، اینترفیس DatabaseConnectionInterface رو ایمپلیمنت کرده و به همین دلیل کلاس PDOQueryBuilder  هم تونسته از متدهای کلاس PDODatabaseConnection استفاده کنه؟ اگه جواب بله هست ممنون میشم یه کم بیشتر در مورد این موضوع توضیح بدید.

فایل پیوست

پویا پارسایی

توسط

پویا پارسایی

9 مهر 00

0
حذف شده

سپاس آقای صالحی

از صحبت های شما و همچنین بقیه تاپیک ها متوجه شدم که اینجا اصل Dependency Inversion رو استفاده کردیم.

پس ما اینجا:

    public function __construct(DatabaseConnectionInterface $connection)
    {
        $this->connection = $connection->getConnection();
    }

در واقع این آبجکتی که از نوع DatabaseConnectionInterface ایجاد کردیم، یه آبجکت از کلاس PDODatabaseConnection هستش که اون اینترفیس رو ایپلیمنت کرده، درسته؟

 

 

تو این حالت ما اگه بخوایم به طور مثال دیتابیس کانکشنمون رو به MySQLI تغییر بدیم، میایم یه کلاس MySQLIDatabaseConnection تعریف میکنیم و اون اینترفیس رو ایمپلیمنت می کنیم و متدهای connect و getConnnect رو پیاده سازی می کنیم.درسته؟

بعد به طور مثال اینجا

public function __construct(DatabaseConnectionInterface $connection)

این کانستراکتور  چجوری باید تشخیص بده که این آبجکتی که بهش پاس داده شده از نوع PDODatabaseConnection هست یا MySQLIDatabaseConnection ؟

فایل پیوست

پویا پارسایی

توسط

پویا پارسایی

10 مهر 00

حذف شده
بله دقیقا مربوط به dependency injection و dependency inversion میشه. contrcutor براش مهم نیست که pdo هست یا mysql بلکه چیزی که براش مهمه باید از نوع DatabaseConnectionInterface باشه حتما، چون اگه این اینترفیس رو implement کرده باشن همون رفتار هارو دارن (connect و getConnection) و میتونن به راحتی جای هم دیگه کار کنن بدون اینکه به مشکلی بخورن
امیر صالحی

13 مهر 00