MVC'de bir model nasıl yapılandırılmalıdır? [kapalı]


551

Ben sadece MVC çerçevesi üzerinde bir kavrayış alıyorum ve genellikle modelde ne kadar kod gitmesi gerektiğini merak ediyorum. Ben böyle yöntemlere sahip bir veri erişim sınıfı var eğilimindedir:

public function CheckUsername($connection, $username)
{
    try
    {
        $data = array();
        $data['Username'] = $username;

        //// SQL
        $sql = "SELECT Username FROM" . $this->usersTableName . " WHERE Username = :Username";

        //// Execute statement
        return $this->ExecuteObject($connection, $sql, $data);
    }
    catch(Exception $e)
    {
        throw $e;
    }
}

Modellerim, veritabanı tablosuyla eşlenen bir varlık sınıfı olma eğilimindedir.

Model nesnesinin tüm eşlenen veritabanı özelliklerinin yanı sıra yukarıdaki kodu içermesi gerekir mi yoksa bu veritabanını gerçekten çalıştıran kodu ayırmak doğru mudur?

Sonunda dört katmanım olacak mı?


133
Neden sadece tekrar atmak için istisnalar yakalıyorsunuz?
Bailey Parker

9
@Elias Van Ootegem: noktayı kaçırdın. bu durumda onları yakalamak anlamsız.
Karoly Horvath

4
@Elias Van Ootegem: ha? eğer yeniden yapmayla çalışırsa, bir üst katmanın istisnayı yakaladığı anlamına gelir. Eğer varsa, o vakit (sen yine de alamazsanız, küçük bir test kodu alay lütfen) ... bu anlamsız rethrow olmadan catched olurdu
Karoly Horvath

3
@Elias Van Ootegem: Ne hakkında konuştuğunuz hakkında hiçbir fikrim yok, belirli bir katmandaki bir istisnayı ele almamak, uygulamayı durduracağı anlamına gelmez. lütfen bu tekrarlamanın gerekli olduğu durumlarda bir kod örneği oluşturun (veya daha doğrusu: yapılamayın). Bu offtopik konuşmayı durduralım, lütfen
Karoly Horvath

6
@drrcknlsn: bu geçerli bir argüman, ancak bu durumda en azından atılmasını beklediğiniz istisnayı yakalayın, jenerik Exceptionçok fazla belge değerine sahip değildir. Şahsen ben bu yolda aşağı inmek ben PHPDoc's @exception, ya da benzer bir mekanizma seçecekti , bu yüzden oluşturulan belgelerde ortaya çıkıyor.
Karoly Horvath

Yanıtlar:


903

Feragatname: Aşağıda, PHP tabanlı web uygulamaları bağlamında MVC benzeri kalıpları nasıl anladığımın bir açıklaması yer almaktadır. İçeriğinde kullanılan tüm harici linkler var terim ve kavramları açıklamak ve vardır değil konu üzerinde kendi itibarını ima etmek.

Temizlemem gereken ilk şey: model bir katman .

İkincisi: Klasik MVC ile web geliştirmede kullandıklarımız arasında bir fark vardır . İşte biraz daha farklı olduklarını kısaca anlatan daha eski bir cevap yazdım.

Bir model DEĞİLDİR:

Model bir sınıf veya tek bir nesne değildir. Yapmak çok yaygın bir hatadır (ben de yaptım, aksi halde öğrenmeye başladığımda orijinal cevap yazılmıştır) , çünkü çoğu çerçeve bu yanlış algıyı sürdürmektedir.

Ne Nesne İlişkisel Haritalama tekniği (ORM) ne de veritabanı tablolarının bir soyutlaması değildir. Size aksini söyleyen herkes büyük olasılıkla başka bir yepyeni ORM'yi veya tüm çerçeveyi 'satmaya' çalışıyor .

Bir model nedir:

Uygun MVC adaptasyon olarak, M tüm alan iş mantığını içerir ve Model Katman edilir çoğunlukla yapıların üç türlerinden yaptı:

  • Alan Nesneleri

    Etki alanı nesnesi, yalnızca etki alanı bilgilerinin mantıksal bir kapsayıcısıdır; genellikle sorun etki alanındaki mantıksal bir varlığı temsil eder. Genellikle iş mantığı olarak adlandırılır .

    Burası, bir fatura göndermeden önce verilerin nasıl doğrulanacağını veya bir siparişin toplam maliyetini nasıl hesaplayacağınızı tanımlar. Aynı zamanda, Alan Nesneler depolama tamamen habersiz - ne den nerede (SQL veritabanı, REST API, metin dosyası, vb) ne de olsa eğer onlar kaydedilen veya alınan olsun.

  • Veri Eşleyicileri

    Bu nesneler yalnızca depolamadan sorumludur. Bir veritabanında bilgi depolarsanız, SQL burada yaşar. Veya veri depolamak için bir XML dosyası kullanırsınız ve Veri Eşleştiricileriniz XML dosyalarından ayrılır .

  • Hizmetler

    Bunları "daha üst düzey Alan Nesneleri" olarak düşünebilirsiniz, ancak iş mantığı yerine Alan Adları Nesneleri ile Haritacılar arasındaki etkileşimden Hizmetler sorumludur . Bu yapılar, alan adı iş mantığı ile etkileşim için bir "genel" arayüz oluşturur. Onlardan kaçınabilirsiniz, ancak bazı etki alanı mantığını Denetleyicilere sızdırma cezasıyla .

    EKL uygulama sorusunda bu konuya ilişkin bir cevap var - yararlı olabilir.

Model katman ile MVC triadının diğer bölümleri arasındaki iletişim sadece Servisler aracılığıyla yapılmalıdır . Açık bir ayrımın birkaç ek faydası vardır:

  • tek sorumluluk ilkesinin (SRP) uygulanmasına yardımcı olur
  • mantığın değişmesi durumunda ek 'kıpır kıpır oda' sağlar
  • denetleyiciyi olabildiğince basit tutar
  • harici bir API'ya ihtiyacınız varsa net bir plan sunar

 

Bir modelle nasıl etkileşim kurulur?

Ön şartlar: izle dersler "Küresel Devlet ve Singletons" ve "Things için Bakma!" Temiz Kod Görüşmelerinden.

Hizmet örneklerine erişim sağlama

Her ikisi için Görünüm ve Denetleyici erişim bu hizmetleri, iki genel yaklaşım vardır için: ( "UI katmanı" Sen buna ne olabilir) örnekleri:

  1. Gerekli hizmetleri, tercihen DI kabı kullanarak doğrudan görüş ve denetleyicilerinizin yapıcılarına enjekte edebilirsiniz.
  2. Tüm görünümleriniz ve denetleyicileriniz için zorunlu bir bağımlılık olarak hizmetler için bir fabrika kullanmak.

Şüphelendiğiniz gibi, DI kabı çok daha zarif bir çözümdür (yeni başlayanlar için en kolay olmasa da). Bu işlevselliği göz önünde bulundurmayı önerdiğim iki kütüphane Syfmony'in bağımsız DependencyInjection bileşeni veya Auryn olacaktır .

Hem fabrika hem de DI kapsayıcısı kullanan çözümler, seçilen denetleyici arasında paylaşılacak çeşitli sunucuların örneklerini paylaşmanıza ve belirli bir istek yanıt döngüsü için görünüm sağlamanıza da olanak tanır.

Modelin durumunun değiştirilmesi

Artık denetleyicilerdeki model katmanına erişebildiğinize göre, bunları gerçekten kullanmaya başlamanız gerekir:

public function postLogin(Request $request)
{
    $email = $request->get('email');
    $identity = $this->identification->findIdentityByEmailAddress($email);
    $this->identification->loginWithPassword(
        $identity,
        $request->get('password')
    );
}

Denetleyicilerinizin çok net bir görevi vardır: kullanıcı girdisini alın ve bu girdiye dayanarak geçerli iş mantığının durumunu değiştirin. Bu örnekte, arasında değiştirilen durumlar "anonim kullanıcı" ve "oturum açmış kullanıcı" dır.

Denetleyici, kullanıcının girişlerini doğrulamaktan sorumlu değildir, çünkü bu iş kurallarının bir parçasıdır ve denetleyici kesinlikle burada veya burada göreceğiniz gibi SQL sorgularını çağırmaz (lütfen onlardan nefret etmeyin, yanlış yönlendirilir, kötülük değildir).

Kullanıcıya durum değişikliği gösteriliyor.

Tamam, kullanıcı giriş yaptı (veya başarısız oldu). Şimdi ne olacak? Sözü edilen kullanıcı hala farkında değil. Yani aslında bir yanıt üretmelisiniz ve bu bir görüşün sorumluluğudur.

public function postLogin()
{
    $path = '/login';
    if ($this->identification->isUserLoggedIn()) {
        $path = '/dashboard';
    }
    return new RedirectResponse($path); 
}

Bu durumda, görünüm model katmanının mevcut durumuna göre iki olası yanıttan birini üretti. Farklı bir kullanım durumunda, "makalenin şu an seçili olanı" gibi bir şeye dayanarak, oluşturulacak farklı şablonlar seçme görünümünüz olur.

Sunu katmanı, burada açıklandığı gibi aslında oldukça ayrıntılı olabilir: PHP'deki MVC Görünümlerini Anlama .

Ama ben sadece bir REST API yapıyorum!

Tabii ki, bu aşırı bir ölüm olduğunda durumlar var.

MVC, Endişelerin Ayrılması ilkesi için somut bir çözümdür . MVC kullanıcı arayüzünü iş mantığından ayırır ve kullanıcı arayüzünde kullanıcı girişi ve sunum işlemlerini ayırır. Bu çok önemli. Çoğu zaman insanlar bunu bir "üçlü" olarak tanımlasa da, aslında üç bağımsız bölümden oluşmuyor. Yapı daha çok şöyle:

MVC ayrımı

Bu, sunum katmanınızın mantığı varolmayana yakın olduğunda, pragmatik yaklaşımın onları tek katman olarak tutmak olduğu anlamına gelir. Ayrıca model katmanının bazı yönlerini önemli ölçüde basitleştirebilir.

Bu yaklaşımı kullanarak giriş örneği (bir API için) şu şekilde yazılabilir:

public function postLogin(Request $request)
{
    $email = $request->get('email');
    $data = [
        'status' => 'ok',
    ];
    try {
        $identity = $this->identification->findIdentityByEmailAddress($email);
        $token = $this->identification->loginWithPassword(
            $identity,
            $request->get('password')
        );
    } catch (FailedIdentification $exception) {
        $data = [
            'status' => 'error',
            'message' => 'Login failed!',
        ]
    }

    return new JsonResponse($data);
}

Bu sürdürülebilir olmasa da, bir yanıt gövdesi oluşturmak için karmaşık bir mantığınız olduğunda, bu basitleştirme daha önemsiz senaryolar için çok yararlıdır. Ama uyarılmalıdır karmaşık sunum mantığı ile büyük codebases kullanmak çalışırken bu yaklaşım, bir kabus haline gelecektir.

 

Model nasıl oluşturulur?

Tek bir "Model" sınıfı olmadığından (yukarıda açıklandığı gibi), gerçekten "modeli oluşturmaz". Bunun yerine belirli yöntemleri uygulayabilen Hizmetler yapmaya başlıyorsunuz . Ve sonra Etki Alanı Nesneleri ve Eşleyicileri uygulayın .

Bir hizmet yöntemi örneği:

Yukarıdaki her iki yaklaşımda da tanımlama hizmeti için bu giriş yöntemi vardı. Aslında neye benzeyecekti. Ben yazdım bir kütüphaneden aynı işlevselliğin biraz değiştirilmiş bir sürümünü kullanıyorum .. çünkü tembel olduğum için:

public function loginWithPassword(Identity $identity, string $password): string
{
    if ($identity->matchPassword($password) === false) {
        $this->logWrongPasswordNotice($identity, [
            'email' => $identity->getEmailAddress(),
            'key' => $password, // this is the wrong password
        ]);

        throw new PasswordMismatch;
    }

    $identity->setPassword($password);
    $this->updateIdentityOnUse($identity);
    $cookie = $this->createCookieIdentity($identity);

    $this->logger->info('login successful', [
        'input' => [
            'email' => $identity->getEmailAddress(),
        ],
        'user' => [
            'account' => $identity->getAccountId(),
            'identity' => $identity->getId(),
        ],
    ]);

    return $cookie->getToken();
}

Gördüğünüz gibi, bu soyutlama düzeyinde verilerin nereden getirildiğine dair bir gösterge yoktur. Bu bir veritabanı olabilir, ama aynı zamanda test amacıyla sadece sahte bir nesne olabilir. Aslında bunun için kullanılan veri eşleştiriciler bile privatebu hizmetin yöntemlerinde gizlidir .

private function changeIdentityStatus(Entity\Identity $identity, int $status)
{
    $identity->setStatus($status);
    $identity->setLastUsed(time());
    $mapper = $this->mapperFactory->create(Mapper\Identity::class);
    $mapper->store($identity);
}

Harita oluşturmanın yolları

Bir kalıcılık soyutlaması uygulamak için, en esnek yaklaşımlar üzerinde özel veri eşleştiriciler oluşturmaktır .

Eşleyici diyagramı

Gönderen: PoEAA kitabı

Uygulamada, belirli sınıflar veya üst sınıflarla etkileşim için uygulanırlar. Diyelim ki kodunuzda Customerve Adminkodunuzda (her ikisi de bir Userüst sınıftan devralma ). Her ikisi de muhtemelen farklı alanlar içerdiğinden, ayrı bir eşleşen haritacıya sahip olacaktır. Ancak, paylaşılan ve yaygın olarak kullanılan işlemlerle de sonuçlanacaksınız. Örneğin: "son çevrimiçi görüldü" zamanının güncellenmesi . Ve mevcut haritacıları daha kıvrımlı hale getirmek yerine, daha pragmatik yaklaşım, yalnızca o zaman damgasını güncelleyen genel bir "Kullanıcı Haritacısı" na sahip olmaktır.

Bazı ek yorumlar:

  1. Veritabanı tabloları ve modeli

    Bazen bir veritabanı tablosu, Etki Alanı Nesnesi ve Eşleyici arasında doğrudan 1: 1: 1 bir ilişki olsa da, daha büyük projelerde beklediğinizden daha az yaygın olabilir:

    • Tek bir Etki Alanı Nesnesi tarafından kullanılan bilgiler farklı tablolardan eşlenebilirken, nesnenin veritabanında kalıcılığı yoktur.

      Örnek: Aylık bir rapor oluşturuyorsanız. Bu, farklı tablolardan bilgi toplar, ancak MonthlyReportveritabanında sihirli bir tablo yoktur .

    • Tek bir Eşleyici birden çok tabloyu etkileyebilir.

      Örnek: Nesneden veri saklarken User, bu Etki Alanı Nesnesi diğer etki alanı nesneleri - Groupörnekleri koleksiyonu içerebilir . Bunları değiştirmek ve saklamak durumunda User, Veri Mapper güncellemesine ve / veya birden tablolarda girdileri eklemek gerekir.

    • Tek bir Etki Alanı Nesnesindeki veriler birden fazla tabloda depolanır.

      Örnek: büyük sistemlerde (düşünün: orta ölçekli bir sosyal ağ), kullanıcı kimlik doğrulama verilerinin ve sık erişilen verilerin nadiren gerekli olan daha büyük içerik yığınlarından ayrı olarak depolanması pragmatik olabilir. Bu durumda hala tek bir Usersınıfınız olabilir, ancak içerdiği bilgiler tüm ayrıntıların getirilip getirilmemesine bağlı olacaktır.

    • Her Etki Alanı Nesnesi için birden fazla eşleyici olabilir

      Örnek: Hem halka açık hem de yönetim yazılımı için paylaşılan kod tabanlı bir haber siteniz var. Ancak, her iki arabirim de aynı Articlesınıfı kullanırken, yönetimin içinde çok daha fazla bilgi bulunması gerekir. Bu durumda iki ayrı eşleyiciniz olur: "dahili" ve "harici". Her biri farklı sorgular gerçekleştirir, hatta farklı veritabanları kullanır (master veya slave'de olduğu gibi).

  2. Görünüm bir şablon değil

    MVC'deki görünüm örnekleri (desenin MVP varyasyonunu kullanmıyorsanız) sunum mantığından sorumludur. Bu, her Görünümün genellikle en az birkaç şablonla oynatılacağı anlamına gelir . Model Katmanından veri alır ve sonra alınan bilgilere dayanarak bir şablon seçer ve değerleri ayarlar.

    Bundan faydalanabileceğiniz faydalardan biri yeniden kullanılabilirliktir. Bir ListViewsınıf oluşturursanız , iyi yazılmış bir kodla, aynı sınıfın bir makalenin altındaki kullanıcı listesi ve yorumların sunumunu vermesini sağlayabilirsiniz. Çünkü ikisi de aynı sunum mantığına sahip. Sadece şablon değiştirirsiniz.

    Ya kullanabilirsiniz doğal PHP şablonlar veya bazı üçüncü taraf şablon motoru kullanmak. View örneklerini tamamen değiştirebilen bazı üçüncü taraf kitaplıkları da olabilir .

  3. Cevabın eski versiyonu ne olacak?

    Tek büyük değişiklik, eski sürümde Model olarak adlandırılan , aslında bir Hizmet olmasıdır . "Kütüphane benzetmesi" nin geri kalanı oldukça iyi bir şekilde devam ediyor.

    Gördüğüm tek kusur, bunun gerçekten garip bir kütüphane olması, çünkü kitaptan bilgi döndürecek, ancak kitabın kendisine dokunmanıza izin vermeyecek, aksi takdirde soyutlama "sızmaya" başlayacaktı. Daha uygun bir benzetme düşünmem gerekebilir.

  4. Görünüm ve Denetleyici örnekleri arasındaki ilişki nedir ?

    MVC yapısı iki katmandan oluşur: ui ve model. UI katmanındaki ana yapılar görünüm ve denetleyicidir.

    MVC tasarım deseni kullanan web siteleriyle uğraşırken, en iyi yol görünümler ve denetleyiciler arasında 1: 1 ilişki kurmaktır. Her görünüm, web sitenizdeki tüm bir sayfayı temsil eder ve söz konusu görünüm için gelen tüm istekleri işlemek üzere özel bir denetleyiciye sahiptir.

    Örneğin, bir açılan makale temsil etmek, sahip olacağını \Application\Controller\Documentve \Application\View\Document. Bu, makalelerle uğraşmak söz konusu olduğunda UI katmanı için tüm ana işlevleri içerir (elbette makalelerle doğrudan ilişkili olmayan bazı XHR bileşenlerine sahip olabilirsiniz ) .


4
@Rinzler, göreceksiniz ki, bu bağlantıda hiçbir yerde, Model hakkında söylenen her şey (bir yorum hariç). Sadece "veritabanı tablolarına nesne yönelimli bir arayüz" . Bunu Model benzeri bir şeyle şekillendirmeye çalışırsanız, SRP ve LSP'yi ihlal edersiniz .
tereško

8
@hafichuk sadece ActiveRecord modelini kullanmanın makul olduğu durumlarda prototip oluşturmak içindir. Üretim için kullanılan kodu yazmaya başladığınızda, bir anti-desen haline gelir, çünkü depolama ve iş mantığını karıştırır. Ve bu yana Modeli Katman diğer MVC parçaların tamamen habersizdir. Bu, orijinal desendeki değişime bağlı olarak değişmez . MVVM kullanırken bile. "Birden fazla model" yoktur ve hiçbir şeyle eşlenmezler. Model bir katmandır.
tereško

3
Kısa Versiyon - Modeller Veri Yapılarıdır .
Eddie B

9
MVC'yi icat ettiğini görmek, makalenin bir değeri olabilir.
Eddie B

3
... hatta sadece bir dizi fonksiyon. MVC, çoğunlukla bu şekilde uygulansa da, OOP tarzında uygulanmasını gerektirmez. En önemli şey katmanları ayırmak ve doğru verileri oluşturmak ve akışı kontrol
etmektir

37

İş mantığı olan her şey bir veritabanı sorgusu, hesaplamalar, bir REST çağrısı vb.

Veri erişiminin modelin kendisinde olmasını sağlayabilirsiniz, MVC kalıbı bunu yapmanızı kısıtlamaz. Şekeri hizmetler, haritacılar ve ne ile kaplayabilirsiniz, ancak bir modelin gerçek tanımı iş mantığını, daha fazlasını değil, daha azını işleyen bir katmandır. İstediğiniz buysa, bir sınıf, bir işlev veya bir gazillion nesnesine sahip eksiksiz bir modül olabilir.

Veritabanı sorgularını doğrudan modelde yürütülmek yerine, aslında veritabanı sorgularını yürüten ayrı bir nesneye sahip olmak her zaman daha kolaydır: bu, özellikle birim test ederken (modelinize sahte bir veritabanı bağımlılığı enjekte etmenin kolaylığı nedeniyle) kullanışlı olacaktır:

class Database {
   protected $_conn;

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

   public function ExecuteObject($sql, $data) {
       // stuff
   }
}

abstract class Model {
   protected $_db;

   public function __construct(Database $db) {
       $this->_db = $db;
   }
}

class User extends Model {
   public function CheckUsername($username) {
       // ...
       $sql = "SELECT Username FROM" . $this->usersTableName . " WHERE ...";
       return $this->_db->ExecuteObject($sql, $data);
   }
}

$db = new Database($conn);
$model = new User($db);
$model->CheckUsername('foo');

Ayrıca, PHP'de nadiren istisnaları yakalamanız / yeniden eklemeniz gerekir, çünkü geri izleme özellikle örneğiniz gibi bir durumda korunur. Sadece istisnanın atılmasına izin verin ve bunun yerine denetleyicide yakalayın.


Yapım çok benzer, sanırım biraz daha ayırıyorum. Bağlantının etrafından geçmemizin nedeni, işlemlerde yığınların çalıştırılması gerektiğiydi. Bir kullanıcı eklemek ve daha sonra bir role kullanıcı eklemek istedim, ancak başarısız olursa geri rol. Bunu çözebilmemin tek yolu bağlantıyı geçmekti.
Dietpixel

10
-1: ayrıca tamamen yanlış olur. Model bir tablo için soyutlama değildir.
tereško

1
UserSınıf temelde modelini genişletir, ancak bir nesne itsn't. Kullanıcı bir nesne olmalı ve aşağıdaki gibi özelliklere sahip olmalıdır: id, name ... UserSınıfı konuşlandırıyorsunuz bir yardımcıdır.
TomSawyer

1
MVC'yi anladığınızı düşünüyorum ama OOP'un ne olduğunu anlamıyorsunuz. Dediğim gibi bu senaryoda, Userbir nesnenin kısaltmasıdır ve CheckUsernameyeni bir Usernesne oluşturmak istiyorsanız ne yapmalısınız ? new User($db)
TomSawyer

@TomSawyer OOP nesnelerin özelliklere sahip olması gerektiği anlamına gelmez. Açıkladığınız, soru ile ilgisi olmayan veya o sorunun cevabı olan bir tasarım deseni. OOP bir tasarım modeli değil bir dil modelidir.
netcoder

20

Web- "MVC" ne istersen yapabilirsin.

Orijinal konsept (1) modeli iş mantığı olarak tanımlamıştır. Uygulama durumunu temsil etmeli ve bazı veri tutarlılığı sağlamalıdır. Bu yaklaşım genellikle "yağ modeli" olarak tanımlanır.

Çoğu PHP çerçevesi, modelin sadece bir veritabanı arayüzü olduğu daha sığ bir yaklaşımı izler. Ancak en azından bu modeller gelen verileri ve ilişkileri hala doğrulamalıdır.

Her iki durumda da, SQL öğelerini veya veritabanı çağrılarını başka bir katmana ayırırsanız çok uzakta olmazsınız. Bu şekilde, gerçek depolama API'sı ile değil, yalnızca gerçek verilerle / davranışlarla ilgilenmeniz gerekir. (Ancak aşırıya kaçmak mantıklı değildir. Örneğin, önceden tasarlanmamışsa, bir veritabanı arka ucunu asla bir dosya deposuyla değiştiremezsiniz.)


8
bağlantı geçersiz (404)
Kyslik


6

Daha oftenly uygulamaların çoğu verileri, ekran ve işleme parçası olacak ve biz sadece harflerle tüm bu koymak M, Vve C.

Modeli ( M) -> uygulama durumunu tutan özelliklerini Has ve hakkında herhangi bir şey bilmiyorum Vve C.

Görünüm ( V) -> Uygulama için görüntüleme formatı vardır ve sadece üzerinde nasıl sindirilecek modeli bilir ve rahatsız etmez C.

Denetleyici ( C) ----> uygulamanın işleme parçası vardır ve M ve V arasındaki kablo olarak hareket eder ve her ikisi de bağlıdır M, Vfarklı Mve V.

Her biri arasında endişe ayrılığı var. Gelecekte herhangi bir değişiklik veya iyileştirme çok kolay bir şekilde eklenebilir.


0

Benim durumumda, sorgulama, getirme ve benzeri gibi tüm doğrudan veritabanı etkileşimini işleyen bir veritabanı sınıfı var. Ben benim veritabanını değiştirmek zorunda Yani eğer MySQL için PostgreSQL herhangi bir sorun olmayacaktır. Bu yüzden, bu ekstra katmanı eklemek yararlı olabilir.

Her tablo kendi sınıfına ve kendine özgü yöntemlere sahip olabilir, ancak aslında verileri almak için veritabanı sınıfının onu işlemesine izin verir:

Dosya Database.php

class Database {
    private static $connection;
    private static $current_query;
    ...

    public static function query($sql) {
        if (!self::$connection){
            self::open_connection();
        }
        self::$current_query = $sql;
        $result = mysql_query($sql,self::$connection);

        if (!$result){
            self::close_connection();
            // throw custom error
            // The query failed for some reason. here is query :: self::$current_query
            $error = new Error(2,"There is an Error in the query.\n<b>Query:</b>\n{$sql}\n");
            $error->handleError();
        }
        return $result;
    }
 ....

    public static function find_by_sql($sql){
        if (!is_string($sql))
            return false;

        $result_set = self::query($sql);
        $obj_arr = array();
        while ($row = self::fetch_array($result_set))
        {
            $obj_arr[] = self::instantiate($row);
        }
        return $obj_arr;
    }
}

Tablo nesnesi classL

class DomainPeer extends Database {

    public static function getDomainInfoList() {
        $sql = 'SELECT ';
        $sql .='d.`id`,';
        $sql .='d.`name`,';
        $sql .='d.`shortName`,';
        $sql .='d.`created_at`,';
        $sql .='d.`updated_at`,';
        $sql .='count(q.id) as queries ';
        $sql .='FROM `domains` d ';
        $sql .='LEFT JOIN queries q on q.domainId = d.id ';
        $sql .='GROUP BY d.id';
        return self::find_by_sql($sql);
    }

    ....
}

Umarım bu örnek iyi bir yapı oluşturmanıza yardımcı olur.


12
"Yani veritabanımı MySQL'den PostgreSQL'e değiştirmek zorunda kalsaydım herhangi bir sorun olmayacak." Yukarıdaki kodu ile Uhhhmmm bir şey imo değiştirme büyük bir sorun olurdu.
PeeHaa

Cevabım düzenlemeden sonra ve zaman geçtikçe daha az anlamlı geliyor. Ama burada kalmalı
Ibu

2
Databaseörnekte bir sınıf değil. Sadece fonksiyonlar için bir sarıcıdır. Ayrıca, bir nesne olmadan nasıl "tablo nesne sınıfı" olabilir?
tereško

2
@ tereško Gönderilerinizin çoğunu okudum ve harikalar. Ancak, çalışılacak hiçbir yerde tam bir çerçeve bulamıyorum. "Doğru mu" diye bir tanesini biliyor musunuz? Ya da en azından biri sizin gibi ve SO'daki bazı diğerleri bunu yapmayı söylüyor? Teşekkürler.
johnny

Çok geç olabilirim, ancak PDO'nun gelecekteki değişiklikleri kolaylaştırmak için bir DB 'katmanı' oluşturmak zorunda kaldığını neredeyse çözdüğünü belirtmek isterim.
Matthew Goulart
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.