2013-11-21 89 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>