2013-11-21 162 views
1

我有一個視圖,它在一個表中顯示了一個由10個數字組成的行(這是一個統計信息顯示板)。正確構建Laravel項目

他們是銷售今天,明天,後天等信息,由一些不同的州分裂。

目前,我有一些這樣的代碼:

class Transaction extends Eloquent { 
    // other methods that aren't relevant 

    public function scopeConfirmed($query) 
    { 
     return $query->where('status', '=', 'Confirmed'); 
    } 

    public function scopeBooked($query) 
    { 
     return $query->where('status', '<>', 'Cancelled'); 
    } 

    public function scopeDaysAhead($query, $days) 
    { 
     $start = \Carbon\Carbon::now()->addDays($days)->toDateString(); 
     $end = \Carbon\Carbon::now()->addDays($days+1)->toDateString(); 
     return $query->where('date', '>=', $start)->where('date', '<', $end); 
    } 

    // few other similar scopes 
} 

然後在我的觀點,我有:

(簡體)

<td> 
    {{Transaction::->daysAhead(0) 
     ->booked() 
     ->count()}} 
</td> 
<td> 
    {{Transaction::->daysAhead(0) 
     ->confirmed() 
     ->count()}} 
</td> 
<td> 
    {{Transaction::->daysAhead(1) 
     ->confirmed() 
     ->count()}} 
</td> 
<td> 
    {{Transaction::->daysAhead(2) 
     ->confirmed() 
     ->count()}} 
</td> 

所以,我負責的口才叫我視圖。實際上銷售人員和地點都有範圍,所以顯示10-20個值。

我可以通過使用非常胖的語句,或者將它放入控制器中的數組中,然後將其移回控制器,但這似乎沒有大量幫助。

處理這個問題的最佳方法是什麼?

回答

3

保持您的視圖儘可能少邏輯,不要讓邏輯混亂你的控制器。對大多數人來說,這意味着將所有的邏輯填充到模型中。這又不是一種有助於編寫可重用且更重要的可測試代碼的方法。

Laravel的IoC容器和依賴注入功能非常強大,應該用於以可測試的方式構建您的應用程序。

我可以理解你爲什麼還想傳遞查詢對象,這是我在模型中用來做的事情。這似乎很有意義,但很快就會發現,使用強大的查詢生成器創建一個嚴格的查詢生成器會創建一些溼代碼。

我的建議是儘可能保持模型苗條,使用它們來創建關係,設置雄辯屬性,驗證規則數組等等。基於接口將所有邏輯抽象爲存儲庫。爲什麼?那麼,接口可以通過IoC綁定到它應該解析的類上,這意味着它可以被依賴注入並輕鬆地交換出來(例如Mockery),同時在您可能想要構建的任何替換中保持結構完整性(Mongo,CouchDB等等實現)。

namespace Repositories; 

interface TransactionInterface { 

    public function findAll(); 
    public function findById($id); 
    public function findByDaysAhead($start = 0, $end = 1) 

} 

而對於倉庫

namespace Repositories; 

use Transaction; 

class TransactionEloquent implements TransactionInterface { 

    public function findAll() 
    { 
     return Transaction::all(); 
    } 

    public function findById($id) 
    { 
     $transaction = Transaction::find($id); 

     if (! $transaction) 
     { 
      throw new Exception("Transaction not found"); 
     } 

     return $transaction; 
    } 

    public function findByDaysAhead($start = 0 , $end = 1) 
    { 
     // Create one query to return all the data you need 
    } 
} 

然後,您可以綁定該存儲庫中的一個新的自定義的ServiceProvider或在您的routes.php

App::bind('Repositories\TransactionInterface', 'Repositories\TransactionEloquent'); 

現在,您可以依賴注入您的控制器的接口,將解析您的雄辯的實現。如果你寫一個不同的存儲庫實現,你可以簡單地把它重新綁定到接口意味着它會被用於任何接口注入(嘲弄類爲例)

class ApplicationController extends BaseController { 

    public function __construct(Repositories\TransactionInterface $interface) 
    { 
     $this->repo = $interface; 
    } 

    public function getIndex() 
    { 
     return View::make('index', array('transactions' => $this->repo->findAll()); 
    } 
} 

在你看來,你只會在需要一個簡單的循環你的數據和輸出,不需要邏輯。

很明顯,你可以把儘可能多的邏輯,你的倉庫喜歡的,你可以看到你的控制器,模型和視圖履行只有他們打算爲責任(OOPS單一職責原則)

這是一個非常什麼是一個非常複雜的問題的簡短答案。我希望這會指導您在Laravel編寫可測試和可重用的模塊化代碼。

一些 '輕' 讀

在哪裏放置文件等

繼PSR-0規範我最終會得到這樣的

- app 
    - {name of app} 
     - Repositories 
      * TransactionInterface.php 
      * TransactionEloquent.php 

結構這兩個文件的命名空間,現在是namespace {name of app}\Repositories

在作曲家中,您可以將其添加到自動載入對象:

"psr-0": { 
    "{name of app}" : "app/" 
} 

這都將PSR-0兼容的命名空間添加到自動加載,當你做出改變,你可以使用

composer dump-autoload 

重建磁帶自動加載機,包括新的文件(並不總是需要的,但是是更好,更快比composer update不斷)。

有多少存儲庫?

我通常最終得到每個模型1+存儲庫。例如,我在前端有一個模型和個人模型的骨幹集合。

使用Backbone.sync(param, collection)將始終使用一個處理輸入作爲模型數組的回購。 Backbone.sync(param, model)將使用處理髮送的單個模型的回購。我也有兩個Laravel資源控制器來處理這個問題。

服務提供商

我把這些在我的應用程序文件夾路徑,我的應用程序在這種情況下

- MFL 
    - Repositories 
    - MFLServiceProvider.php 

config\app.php

內容添加到我的服務提供商陣列稱爲「MFL」
namespace MFL; 

use Illuminate\Support\ServiceProvider; 

class MFLServiceProvider extends ServiceProvider { 

    public function register() 
    { 
     // Register bindings here, don't use other service providers here 
     // you can't be sure they are loaded as of yet 
     $this->app->bind('MFL\Repositories\TransactionInterface', 'MFL\Repositories\TransactionEloquent'); 
    } 

    public function boot() 
    { 
     // Do anything else here with assurance all service providers are 
     // fully loaded and the application is ready 
    } 
} 

使用此方法,您不會污染routes.php與IoC綁定和喲你可以從邏輯上將你的所有代碼分割成服務。這是我後一種理由的首選方法。

+0

這個答案聽起來正是我一直在尋找。對於前兩個代碼片段,我應該在哪裏放置這些代碼片段?我如何確保他們正確加載?你會建議擁有許多'存儲庫',每個模型一個?最後,「您可以將這個存儲庫綁定到一個新的自定義ServiceProvider中」 - 這兩件事是完全相同的,還是有理由選擇另一個呢?非常感謝! –

+1

@我傾向於在'/ app'內創建一個新的文件夾,其中包含我的應用程序的命名空間,遵循PSR-0規範。然後我使用作曲家PSR-0加載功能。我會爲你添加這個和更多的答案。 –

0

視圖作曲家有第三種選擇。在最基本的層次上,這些都包含在routes.php中,但我想通過視圖路徑將它們分開,以便Composers/transactions.php能夠處理視圖/事務中的所有視圖,如「transactions.dashboard」。考慮到作爲一個視圖,然後作曲家會...

View::composer('transactions.dashboard', function ($view) 
{ 
    $view->day0_count = Transaction::->daysAhead(0) 
     ->booked() 
     ->count(); 
} 

$ day0_count現在在視圖中可用。

<td>{{ $day0_count }}</td>