在返回的数据库对象上运行字符串函数的最佳方法

时间:2016-10-26 02:00:27

标签: php laravel laravel-5

在使用Laravel 5.3将数据发送到视图之前,我需要对从数据库返回的数据运行各种字符串函数。 str_replace()等基本内容。

现在也许有一种很好的方法可以在我的模型上设置Accessors,并以某种方式在着陆页上使用该模型,但我想我会采用不同的路线,只需在模型外部手动执行此查询。

所以我有一个视图提供程序,可以成功地将我的数据导入到视图中。它看起来像这样:

   <table border="1">
    <tr>
        <td onmousedown="highlight(this);">Cell 1</td>
        <td onmousedown="highlight(this);">Cell 2</td>
        <td onmousedown="highlight(this);">Cell 3</td>
    </tr>
    <tr>
        <td onmousedown="highlight(this);">Cell 4</td>
        <td onmousedown="highlight(this);">Cell 5</td>
        <td onmousedown="highlight(this);">Cell 6</td>
    </tr>
    <tr>
        <td onmousedown="highlight(this);">Cell 7</td>
        <td onmousedown="highlight(this);">Cell 8</td>
        <td onmousedown="highlight(this);">Cell 9</td>
    </tr>
</table>

然后在视图中循环并且一切正常

var valueDateDay = 1000;
Console.WriteLine(valueDateDay.ToString(valueDateDay.ToString().Length > 4 ? "N0" : "C2"));
valueDateDay = 100000;
Console.WriteLine(valueDateDay.ToString(valueDateDay.ToString().Length > 4 ? "N0" : "C2"));

正如您在上面的示例中所看到的,我使用 - &gt; each()运行数据集合的str_replace(),并且我正在努力让我做一个我需要进行的简单字符串替换。

然而,作为Laravel,我确信有一些魔法可以被拉到这里以更聪明地做到这一点。

在实际的数据库请求代码中是否有一种方法可以指定要返回的某个列应该自动运行一个函数?

为了澄清,我想在提供者php而不是视图文件中进行这些更改,我想在具有Accessors的模型之外进行此操作。

5 个答案:

答案 0 :(得分:5)

您可以将选择查询编写为:

$featuredProperties = DB::table('properties')
    ->where([
        ['featured_property', '=', '1'],
        ['supplier_id', '=', 123],
    ])
    ->select('*', DB::raw("replace(prop_url, 'http://domain.com/', 'http://www.domain.com/') as new_prop_url"))
    ->orderBy('prop_id', 'desc')
    ->limit(6)
    ->get();

然后在您看来,您可以这样做:

@if(isset($featuredProperties))
   @foreach ($featuredProperties as $property)
       <li>
           <a title="{{ $property->prop_name }}" href="{{ $property->new_prop_url }}"></a>
       </li>           
  @endforeach
@endif

答案 1 :(得分:2)

这对于Presenter模式来说是一个很好的用例。有一些Laravel软件包可以帮助解决这个问题,但最新的软件包看起来像mccool/laravel-auto-presenter

该软件包背后的想法是,您将创建一个Presenter对象,它包装需要显示信息的ModelPresenter对象包含视图所需的任何数据转换的所有逻辑。

这是未经测试的,但下面显示了一个示例实现。创建一个app\Presenters目录,并添加以下文件:

应用\演示\ PropertyPresenter.php

namespace App\Presenters;

use App\Property;
use McCool\LaravelAutoPresenter\BasePresenter;

class PropertyPresenter extends BasePresenter
{
    // this parameter MUST be named $resource
    public function __construct(Property $resource)
    {
        $this->wrappedObject = $resource;
    }

    // create functions for any properties you'd like to present
    public function prop_url()
    {
        return str_replace("http://domain.com/", "http://www.domain.com/", $this->wrappedObject->prop_url);
    }

    // you can also create functions for properties that don't actually
    // exist on the model. in view, access via $property->secure_prop_url
    public function secure_prop_url()
    {
        return str_replace("http:", "https:", $this->prop_url);
    }
}

现在,您需要修改Property模型以告知其演示者。它需要实现HasPresenter接口并定义getPresenterClass()方法。

namespace App;

use App\Presenters\PropertyPresenter;
use Illuminate\Database\Eloquent\Model;
use McCool\LaravelAutoPresenter\HasPresenter;

class Property extends Model implements HasPresenter
{
    public function getPresenterClass()
    {
        return PropertyPresenter::class;
    }
}

最后,所有这些逻辑都取决于实际访问视图中的Property模型。您当前的逻辑正在使用DB::table('properties'),这将创建CollectionstdClass个对象。这需要更改为实际使用您的Property模型,因此您的视图将获得CollectionProperty模型。

class ViewLandingProvider extends ServiceProvider {
    public function boot() {
        // process when featured homepage element is present...
        View::composer('mybladetemplate', function ($view) {

            $featuredProperties = \App\Property::where([
                    ['featured_property', '=', '1'],
                    ['supplier_id', '=', 123],
                ])
                ->orderBy('prop_id', 'desc')
                ->limit(6)
                ->get();

            View::share('featuredProperties', $featuredProperties);
        });
    }
}

您的观点根本无需更改。

答案 2 :(得分:2)

在查询中替换字符串的最佳方法是使用用户sql replace函数。使用大型数据集时,使用php替换字符串存在性能问题。 Laravel可以方便地扩展Builder中的构建,因此您不必编写原始查询。这是一个如何做的例子。

<?php

namespace App\Providers;

use Illuminate\Database\Query\Builder;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        //
    }

    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        Builder::macro('replace', function ($column, $searchText, $replaceText)
        {
            return $this->addSelect(DB::raw("replace($column, '$searchText', '$replaceText') as $column"));
        });


 }
}

在查询构建器中注册了此Macro后,您的查询将如下所示。

$featuredProperties = DB::table('properties')
            ->where([
                ['featured_property', '=', '1'],
                ['supplier_id', '=', 123],
            ])
            ->replace('prop_url', 'http://domain.com/', 'http://www.domain.com/')
            ->orderBy('prop_id', 'desc')
            ->limit(6)
            ->get();

答案 3 :(得分:2)

我想你可能正在寻找一个集合宏。您可以在AppServiceProvider中注册,如:

Collection::macro('formatPropUrl', function() {

    return collect($this->items)->map(function($property) {
        $property->prop_url=str_replace("http://domain.com/","http://www.domain.com/",$property->prop_url);

        return $property;
    });

});

然后,您可以执行以下查询:

$featuredProperties = DB::table('properties')
    ->where([
        ['featured_property', '=', '1'],
        ['supplier_id', '=', 123],
    ])
    ->orderBy('prop_id', 'desc')
    ->limit(6)
    ->get()
    ->formatPropUrl();

答案 4 :(得分:1)

get()的{​​{1}}方法返回Illuminate\Database\Query\Builder的实例。该类提供了许多操作数据集合的方法。

您可以在documentation中了解更多信息。