MVC در PHP قسمت سوم :: Model

شهریور ۱۶, ۱۳۹۲ توسط : سعید

سلام

در این قسمت از سری مقالات MVC در PHP  به لایه Model میپردازیم.همینطور که در قسمت اول اشاره شد لایه Model وظیفه ارتباط با پایگاه داده رو داره. در معماری MVC و کلا سیستم هایی که به صورت شیء گرا نوشته میشن معمولا برای هر کدوم از جدولهای دیتابیس یک کلاس جدا باید داشته باشیم.

این به این خاطره که کار نگهداری و گسترش در آینده به راحتی انجام بشه .حالا ما هم در این فریم ورک از این روش استفاده میکنیم.

لایه Model ( در فریم ورک ما ) برای ارتباط با دیتابیس باید قابلیت های زیر رو داشته باشه :

برای داشتن یک فریم ورک خوب و کاربردی باید یک سری پیش نیازها رو قبل از پیاده سازی لایه Model انجام بدیم.پس قبل از پیاده سازی لایه مدل ما به کلاس های زیرنیاز داریم :

کلاس Config برای نگهداری تنظیمات

کلاس SqlQuery برای ارتباط با پایگاه داده و اجرای عملیات رو جدول مورد نظر

خوب با هم اولین قسمت رو که نوشتن کلاس Config هست انجام میدیم

این کلاس وظیفه نگهداری تنظیمات کلی فریم ورک رو بر عهده داره.برای اینکه تنظیمات رو یه جایی نگهداری کنیم راههای مختلفی وجود داره.میتونه این تنظیمات به صورت یک کلاس باشه یا میتونه در یک فایل با پسوند ini ذخیره بشه. برای اینکار ما از یک فایل با نام config.ini و یک کلاس برای دسترسی به تنظیمات ذخیره شده توی این فایل نیاز داریم.

یک فایل با نام config.ini توی پوشه library  بسازید با این محتویات :

[database]
driver = "Mysql"
dbName = "phpromvc"
dbUsername = "root"
dbPassword = ""

خب یک کلاس با نام Config.php در پوشه library بسازید :

<?php

class Config {

    static function get($key) {
        $config = parse_ini_file(LIB_DIR.DS. 'config.ini');
        return $config[$key];
    }

}

توی این کلاس با استفاده از تابع parse_ini_file  محتویات فایل config.ini رو به صورت آرایه در اختیار داریم و سپس با متد Config::get میتونیم به تنظیماتمون دسترسی داشته باشیم.

شاید بپرسید چرا از یک فایل ini برای تنظیمات استفاده کردم.جوابم اینه که میخواستم توی این آموزش یک چیز جدید رو باهم تجربه کنیم.شما از هر روشی که دوست دارید میتونید استفاده کنید.

مشکلی که این روش داره اینه که اگر کاربر آدرس فایل config.ini رو مستقیم توی مرورگر وارد کنه به تنظیمات ما دستری پیدا میکنه که از لحاظ امنیتی مشکل داره.برای رفع این مشکل خط زیر رو به فایل htaccess اضافه میکنیم :

<Files *.ini> 
    Order deny,allow
    Deny from all
</Files>

که دسترسی مستقیم به این فایل رو غیرممکن میکنه.

بریم به ادامه مطلب که این بار باید کلاسی بسازیم برای ارتباط و انجام عملیات روی دیتابیس.

برای اینکه فریم ورکمون انعطاف بیشتری داشته باشه باید کلاسی بنویسیم که بتونه با انواع دیتابیس ها ارتباط برقرار کنه.ما کلاس PDO رو انتخاب میکنیم که از هر لحاظ میتونه به ما کمک کنه :

<?php

class Model {

    private $_pdo ;
    private $_query = '';
    protected $table = '';
    protected $pk = '';

    function __construct() {

        $dns = Config::get("driver");
        $dbName = Config::get("dbName");
        $username = Config::get("dbUsername");
        $password = Config::get("dbPassword");

        if($this->table == ''){
            $this->table = get_class($this);
        }

        $this->_pdo= new PDO($dns . ':host=localhost;dbname=' . $dbName, $username, $password);
    }

    function get_rows($fields = '*', $where = ' 1=1 ', $order = 'ASC', $limit = 10) {
        $this->_query = "select $fields from {$this->table} where {$where} ORDER BY {$this->pk} $order LIMIT $limit";
        $stm = $this->_pdo->query($this->_query);
        return $stm->fetchAll();
    }

    function get_row($fields = '*', $where = ' 1=1 ', $order = '', $limit = 10) {
        $this->_query = "select $fields from {$this->table} where {$where} ORDER BY {$this->pk} $order LIMIT $limit";
        $stm = $this->_pdo->query($this->_query);
        return $stm->fetch();
    }

    function delete($id) {
        $this->_query = "delete from $this->table where id = '$id'";
        $this->_pdo->exec($this->_query);
    }

    function update($data, $where = ' 1 = 1 ') {
        $this->_query = " update {$this->table} set $data where $where";
        $this->_pdo->exec($this->_query);
    }

    function insert($fields, $data) {
        $this->_query = " insert into $this->table ($fields) VALUES ($data)";
        $this->_pdo->exec($this->_query);
    }

    function run($query) {
        $this->query = $query;
        $this->_pdo->exec($query);
    }

    function last_query(){
        return $this->_query;
    }
}

این کلاس خیلی ساده است که امکان اضافه / حذف / ویرایش و انجام کوئری های مورد نظرمون رو میده.

یک دیتابیس با یک جدول بسازید. اسم جدول رو بذارید “articles” و فیلدهای زیر رو بهش اضافه کنید :

حالا چندتا ردیف با مقادیر دلخواه به این جدول اضافه کنید.

یک پوشه با نام model در پوشه ی app بسازید. یک کلاس در این پوشه با نام articles.php ایجاد کنید و کدهای زیررو داخلش قرار بدید :

<?php

class articles extends Model{
    protected $table = 'articles';
    protected $pk = 'id';
}

همینطور که قبلا هم اشاره کردم نام کلاس باید با نام جدول همنام باشن. کلاس articles از کلاس Model ارث بری کرده و به تمام متدهای public و protected اون دسترسی داره. متغیر $table نام جدول رو میگیره که اگر خالی باشه نام کلاس به عنوان نام جدول در نظر گرفته میشه و متغیر $pk نام کلید اصلی رو نگهداری میکنه.

قبل از اینکه کاری انجام بدید یک نکته دیگه رو هم باید اشاره کنم. در سیستم های بزرگ برای جلوگیری از include های پی در پی از تابع autoload استفاده میکنن.

با استفاده از کلاس Load ما دیگه نیازی به include کردن کلاسهامون نداریم.

کدهای زیر رو به فایل index.php اضافه کنید :

define("LIB_DIR" , ROOT.DS.'library');
define("APP_DIR" , ROOT.DS.'app');
include LIB_DIR.DS.'Load.php';
spl_autoload_register(array('Load', 'autoload'));

و کلاس Load در پوشه library :

<?php

class Load {

    static function autoload($class) {
            include LIB_DIR . DS . $class . '.php';
    }

    static function model($modelName) {
        if(file_exists($file = APP_DIR.DS.'model'.DS.$modelName.'.php')){
            include $file;
            return new  $modelName();
        }
    }
}

با استفاده از متد model میتونیم model مورد نظرمون رو load کنیم.

توی کنترلر ArticleController متد view رو اضافه کنید :

<?php

class ArticleController{

    function index(){
        echo 'IndexController -> index action';
    }

    function view($id){
        $article = Load::model("articles");
        $row = $article->get_row('*' , " id = $id ");
        print_r($row);
        echo $article->last_query();
    }
}

با رفتن به آدرس زیر میتونید نتیجه رو مشاهده کنید :

۱۲۷٫۰٫۰٫۱/article/view/2

خب این قسمت هم به پایان رسید.امیدوارم که مفید بوده باشه.اگر نظر یا سوالی در مورد آموزشها دارن میتونن زیر همین مقاله نظر خودشون رو بگن.اگر هم مشکلی توی آموزشها میبینید میتونید بازهم همینجا بگید خوشحال میشم.

در قسمتهای بعدی به بررسی لایه های Controller و View میپردازیم.

موفق باشید

بازدید : ۱۴۹۹۴

شهریور ۱۸, ۱۳۹۲ @ ۱۲:۵۱ ق.ظ

عالی بود …

پاسخ دادن
شهریور ۱۸, ۱۳۹۲ @ ۱۱:۵۹ ق.ظ

با سلام

من میخواستم بدونم برای سایتهای بزرگی چون فیس بوک و یا آمازون هم از این روش استفاده کردن یا نه

میدونید مشکل من اینه که نمی تونم درک کنم که یک روش باشه که همه از اون روش برای برنامه نویسی استفاده کنن

راههای زیادی هستش و هر کسی سبک خواصی برای خودش داره مثلا همین MVC برای طراحی سیستم های عمومی بهتر جواب میده از نظر ارتقاع و یا فراگیر شدن ولی برای سیستم های شخصی هم میشه استفاده کرد ولی لزومی نداره که حتما از این روش استفاده کرد

پاسخ دادن
    سعید
    شهریور ۱۸, ۱۳۹۲ @ ۲:۵۹ ب.ظ

    سلام
    سایتهای بزرگ مثل فیسبوک معمولا از روشهای خودشون استفاده میکنن.اما چیزی که مهمه اینه که این سایتهای به دلیل گستردگی باید قابل نگهداری و تغییر باشن.
    من نمیدونم اونا از چه راهی برای پیاده سازی سایتهاشون استفاه کردن ولی اینو میدونم که معماری سه لایه یکی از بهترین معماری ها برای طراحی سایتها به حساب میاد.
    اینکه میگید راههای زیادی هست کاملا حرف درستیه اما باید این نکته رو هم در نظر گرفت که مثلا شما یک سایت با روش خودت مینویسی که بعدها قرار کس دیگه ای اون رو گسترش بده.در این حالت برای اینکه بقیه توسعه دهنده ها به مشکل نخورن باید داکیومنت بسیار بزرگی داشته باشی. اما اگر به روشهای معمول کد نویسی کنی میتونی نیاز به توضیح در مورد روش طراحی نداری دیگه و با یک داکیومنت جمع و جور هر کسی میتونه کار شما رو ادامه بده.
    موفق باشید

    پاسخ دادن
آبان ۵, ۱۳۹۲ @ ۱۱:۱۳ ب.ظ

با تشکر از مقاله آموزنده و مفیدتون
میشه بگین کلاس model رو کجا باید ایجاد کنیم
و لطفا یکم توضیح بدین که فایل articles.php که داخل پوشه model ساختیم چطور از این کلاس استفاده میکنه من یکم گیج شدم الان تو این فایل فقط اسم جدول و کلید اصلی رو مشخص کردیم آیا تنها کاری که تو لایه model باید انجام بشه همینه؟

پاسخ دادن
    سعید
    دی ۲, ۱۳۹۲ @ ۱:۱۹ ب.ظ

    سلام
    اگر یکبار ( یا چند بار) دیگه کدها رو بررسی کنید میفهمید که چطور این لایه ها باهم ارتباط دارن. لایه مدل رو باید در پوشه app/model قرار بدین و نام کلاس باید همنام با جدول دیتابیس باشه. در لایه مدل دستورات مربوط به کار با دیتابیس انجام میشه.
    موفق باشید

    پاسخ دادن
      دی ۹, ۱۳۹۲ @ ۸:۳۶ ب.ظ

      البته اگه منظورشون فایل Model.php است ، توی پوشه library ذخیره میشه (بر اساس پروژه ای که در همین سایت گذاشته شده).
      موفق باشید.

      پاسخ دادن
آبان ۱۰, ۱۳۹۲ @ ۷:۳۲ ب.ظ

سلام.
کد زیر خطا می دهد:
$this->_pdo= new PDO($dns . ‘:host=localhost;dbname=’ . $dbName, $username, $password);

متن خطا:
Fatal error: Uncaught exception ‘PDOException’ with message ‘could not find driver’ in E:\Program Files\Wamp Server\www\MVC Testing\Part 03\library\model.php on line 15

( ! ) PDOException: could not find driver in E:\Program Files\Wamp Server\www\MVC Testing\Part 03\library\model.php on line 15

پاسخ دادن
    سعید
    آبان ۱۲, ۱۳۹۲ @ ۹:۴۸ ق.ظ

    توی فایل کانفیگ درایور دیتابیس رو درست وارد کنید

    پاسخ دادن
آبان ۱۲, ۱۳۹۲ @ ۹:۰۵ ب.ظ

آقا بسیار عالی بود واقعا خسته نباشید متشکرم

پاسخ دادن
دی ۲, ۱۳۹۲ @ ۱۰:۵۶ ق.ظ

سلام خدمت شما استاد گرامی
من هم مشکل آقای morteza را دارم
فایل config.ini هم به شکل زیر است
[database]
driver = “Mysql”
dbName = “phpromvc”
dbUsername = “root”
dbPassword = “123”

مشکل از کجاست؟؟؟؟

پاسخ دادن
    دی ۲, ۱۳۹۲ @ ۱۲:۰۴ ب.ظ

    باید Mysql رو به صورت “mysql می نوشتم”
    حالا مشکل جدید دارم
    Fatal error: Call to undefined method articles::get_row() in C:\wamp\www\bookstor\app\controller\article.php on line 11
    ریز به ریز کلمات رو گشتم غلط املایی هم ندارم لطفا راهنمایی کنید ضمنا میشه فایل پروژه رو آپلود کنید

    پاسخ دادن
      سعید
      دی ۲, ۱۳۹۲ @ ۱۲:۵۵ ب.ظ

      سلام
      ببخشید که دیر جواب دادم. کدهایی که نوشتین رو بذارین تا ببینیم مشکل کجاست

      پاسخ دادن
        دی ۴, ۱۳۹۲ @ ۱۲:۱۹ ب.ظ

        سلام مجدد
        خواهش میکنم شما سرور مایی
        کدها رو توی لینک زیر قرار دادم
        imensystem.net\mvc.zip
        با تشکر

        پاسخ دادن
        دی ۲۲, ۱۳۹۲ @ ۵:۲۸ ب.ظ

        منم مثل ایشون ، فهمیدین مشکل کجاست؟

        پاسخ دادن
دی ۹, ۱۳۹۲ @ ۱۰:۵۷ ب.ظ

سلام. خسته نباشید.
بازم به خاطر مقالات خوبتون تشکر می کنم.
آقا من به مشکلی برخورد کردم و در نهایت بر اساس پروژه ای که برای دانلود گذاشته بودید فهمیدم که کلمه Mysql در فایل کانفیگ باید به صورت mysql نوشته شود.
اگر انتقاد من درست است این کلمه را که در همین مقاله اشتباه نوشته شده ، درست کنید.
با تشکر فراوان.
موفق و پیروز باشید.

پاسخ دادن
دی ۲۲, ۱۳۹۲ @ ۲:۴۸ ب.ظ

سلام دوست عزیز تو مال من به این خط اشکال میگیره
$this->_pdo= new PDO($dns . ‘:host=localhost;dbname=’. $dbName, $username, $password);
تو درایور
یکی این
Fatal error: Uncaught exception ‘PDOException’ with message ‘could not find driver’ in C:\wamp\www\CMS\library\Model.php on line 21
یکی این
PDOException: could not find driver in C:\wamp\www\CMS\library\Model.php on line 21

پاسخ دادن
    سعید
    دی ۲۲, ۱۳۹۲ @ ۳:۴۶ ب.ظ

    درایور رو توی فایل config باید به صورت زیر وارد کنید :

    [database]
    driver = "mysql"
    dbName = "dbname"
    dbUsername = "dbuser"
    dbPassword = "dbpass"
    
    
    پاسخ دادن
      دی ۲۲, ۱۳۹۲ @ ۴:۰۲ ب.ظ

      سلام من این مشکلم مثل دوستمون حل کردم بعدش ایرادی که پیش میاد اینه
      ( ! ) Fatal error: Cannot redeclare class articles in C:\wamp\www\CMS\app\model\articles.php on line 5
      در فایل articles به نمیدونم چی چی اشکال میگیره برام عجیب بود چون لاین ۵ کاراکتر { هستش که کلاس رو بسته

      پاسخ دادن
بهمن ۱۳, ۱۳۹۲ @ ۱۲:۴۲ ق.ظ

سلام
اگه فایل کامل رو برای دانلود می زاشتین عالی بود

پاسخ دادن
اسفند ۱۴, ۱۳۹۲ @ ۴:۲۷ ب.ظ

سلام
من طبق راهنمایی های شما پیش رفتم ولی نمی تونه فایل load رو پیدا کنه و خطا میده
Warning: include() [function.include]: Unable to access /home3/amardsho/public_html/123/library/Load.php in /home3/amardsho/public_html/123/index.php on line 16

Warning: include(/home3/amardsho/public_html/123/library/Load.php) [function.include]: failed to open stream: No such file or directory in /home3/amardsho/public_html/123/index.php on line 16

Warning: include() [function.include]: Unable to access /home3/amardsho/public_html/123/library/Load.php in /home3/amardsho/public_html/123/index.php on line 16

Warning: include(/home3/amardsho/public_html/123/library/Load.php) [function.include]: failed to open stream: No such file or directory in /home3/amardsho/public_html/123/index.php on line 16

Warning: include() [function.include]: Failed opening ‘/home3/amardsho/public_html/123/library/Load.php’ for inclusion (include_path=’.:/usr/lib/php:/usr/local/lib/php’) in /home3/amardsho/public_html/123/index.php on line 16

Fatal error: Uncaught exception ‘LogicException’ with message ‘Passed array does not specify an existing static method (class ‘Load’ not found)’ in /home3/amardsho/public_html/123/index.php:17 Stack trace: #0 /home3/amardsho/public_html/123/index.php(17): spl_autoload_register(Array) #1 {main} thrown in /home3/amardsho/public_html/123/index.php on line 17

پاسخ دادن
    سعید
    اسفند ۱۵, ۱۳۹۲ @ ۹:۰۵ ق.ظ

    سلام
    لطفا کدهاتون رو بذارید تا ببینیم مشکل کجاست

    پاسخ دادن
اسفند ۱۷, ۱۳۹۲ @ ۱۰:۳۰ ق.ظ

سلام مشکل قبلی من حل شد الان من یک سوال دارم اگه بخوام به فریم وورکم یک themplate اضافه کنم چه جوری باید این کارو انجام بدم؟ اگه راهنماییم کنید ممنون میشم

پاسخ دادن
فروردین ۲۵, ۱۳۹۳ @ ۱۱:۱۲ ب.ظ

ممنون

پاسخ دادن
علی
خرداد ۹, ۱۳۹۳ @ ۳:۳۷ ب.ظ

با سلام خدمت شما

من تمام مراحل را تا این قسمت دنبال و اجرا کردم اما با این پیغام ها مواجه شدم
http://www.uplooder.net/img/image/82/8b8e8b387d62c01d8aef4ec107bba2e4/mvc.png

میشه بگین مشکل از کجاست؟؟

این هم آدرس کل فایل هام به جز دیتابیس.

پاسخ دادن
    سعید مقدم زاده
    خرداد ۱۰, ۱۳۹۳ @ ۹:۰۸ ق.ظ

    سلام
    فایلهاتون رو برام ایمیل کنید تا ببینم مشکل کجاست.

    پاسخ دادن
حمزه
خرداد ۱۶, ۱۳۹۳ @ ۱۱:۵۵ ب.ظ

با سلام
دوستان من کاملا طبق مطالب پیش رفتم و کار میکنه و مشکلی پیش نمیاد
به حروف بزرگ و کوچک بودن نام فایلها و دایرکتوری ها دقت کنید
و اینکه کلاس class Model رو نگفته که یه فولدر بنام Model در پوشه librery بسازید
تنها یه مشکل وجود داره و اون اینه که وقتی ما آی دی خبری رو میخوایم که در بانک اطلاعاتی موجود نیست اونوقت کد کوئری رو چاپ میکنه!! چرا؟
بطور مثال:اگر ما بزنیم article/view/300
خروجی:
select * from articles where id = 300 ORDER BY id LIMIT 10

پاسخ دادن
حمزه
خرداد ۱۷, ۱۳۹۳ @ ۱۲:۰۱ ق.ظ

خب پاسخ رو پیدا کردم
در کلاس ArticleController که تو فولدر کنترلر و فایل مربوطه هستش
درون تابه view:
echo $article->last_query
رو پاکش کنید
ممنون از تمام دست اندر کاران
آموزش راحت تر از این پیدا نمیشه تو وب+خیلی خوب

پاسخ دادن
مهدی
اسفند ۹, ۱۳۹۳ @ ۶:۱۰ ب.ظ

به من یه همچین اروری داده!

Fatal error: Class ‘Load’ not found in C:\xampp\htdocs\armesweb-php\app\Controller\user.php on line 10
انگار کلاس لود رو پیدا نمیکنه!

پاسخ دادن
علی
شهریور ۶, ۱۳۹۴ @ ۲:۳۹ ب.ظ

مرسی از آموزش مفیدتون

کلاس pdo من مشکلی نداره و توابع خوب کار می کنن. اما برای راحتی کار تو دریم ویور توابع pdo بصورت auto complete (وقتی ctrl+space) رو می گیرم نشون داده نمیشه. تو بقیه text editorهام هم نشون نمیده. مشکل از کجاست؟

پاسخ دادن
    Saeed Moqadam
    شهریور ۷, ۱۳۹۴ @ ۵:۰۵ ب.ظ

    سلام
    دریم ویور رو بذار کنار و از یکی دیگه از IDE ها استفاده کن. مثل PHP Storm که امکانات بسیار بیشتری داره

    پاسخ دادن
fateme
آبان ۱۰, ۱۳۹۴ @ ۱۰:۳۸ ق.ظ

salam
mamnoon az amozeshetoon
man ham toye ghesmat load cllass “load” porojam moshkel dare vali dasty oon bala load ro include kardam dorost shod vali alan dobare
Fatal error: Call to undefined method articles::get_row() in C:\wamp\www\bookstor\app\controller\article.php on line 11
in error ro dare

پاسخ دادن
    fateme
    آبان ۱۰, ۱۳۹۴ @ ۱۰:۳۹ ق.ظ

    میشه راهنماییم کنید

    پاسخ دادن
      fateme
      آبان ۱۰, ۱۳۹۴ @ ۱۱:۳۲ ق.ظ

      وای مرسی
      پروژه رو از قسمت قبل دانلود کردم مشکلم حل شد
      بازم ممنون

      پاسخ دادن

پاسخ دهید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *


*