雄辩|在插入时设置列值

时间:2018-03-17 10:04:21

标签: laravel symfony eloquent

所以目前,我有一个用于商业地点的表格,以便从实际的商家表格中分隔这些地点。

在此表中,我想存储经度和纬度,显然我无法让用户输入,而不需要他们做我真正想要避免的手动工作。

所以我写了一个课程,以便为进入数据库准备好经度和纬度。

我已经在线阅读了关于在模型中执行setLongitudeAttribute()功能的内容,但我将它从他们输入的整个地址中删除,因此我需要捕获整个请求,然后把它输入我自己。

我知道我可以在控制器中执行此操作并执行自定义插入,但我不知道是否可以将其全部包含在模型中。

所以基本上要打破它。

  • 用户输入完整地址,包括所有地址行和邮政编码。
  • Eloquent模型捕获此数据。
  • 将地址转换为long和lat
  • 模型然后处理请求,以便根据地址设置经度和纬度。

    <?php
    
    namespace App\Models;
    use Illuminate\Database\Eloquent\Model;
    use App\Http\Calls\LongitudeLatitude;
    
    class BusinessLocation extends Model
    {
        /**
         * @var array
         */
        protected $fillable = [
            'business_id',
            'address_line_1',
            'address_line_2',
            'address_line_3',
            'address_line_4',
            'postcode',
            'longitude',
            'latitude'
        ];
        /**
         * @var string
         */
        protected $address;
    
    protected function setAddressLine1Attribute($value)
    {
        $this->address .= $value . '+';
        $this->attributes['address_line_1'] = $value;
    }
    
    protected function setAddressLine2Attribute($value)
    {
        $this->address .= $value . '+';
        $this->attributes['address_line_2'] = $value;
    }
    
    protected function setAddressLine3Attribute($value)
    {
        $this->address .= $value . '+';
        $this->attributes['address_line_3'] = $value;
    }
    
    protected function setAddress4Attribute($value)
    {
        $this->address .= $value . '+';
        $this->attributes['address_line_4'] = $value;
    }
    
    protected function setPostcodeAttribute($value)
    {
        $this->address .= $value;
        $this->attributes['postcode'] = $value;
        $this->setCoordinates();
    }
    
    protected function setCoordinates()
    {
        $long_lat = new LongitudeLatitude();
        $coords = $long_lat->get($this->address);
    
        $this->attributes['longitude'] = $coords['longitude'];
        $this->attributes['latitude'] = $coords['latitude'];
    }
    

1 个答案:

答案 0 :(得分:0)

首先,正如你正确提到的那样,在模型中编写这个逻辑并不是一个很好的做法,但是在控制器中。

如果我是你,我会将模型逻辑留给模型,其余部分留给控制器和其他对象,以及#34;转换&#34;输入。这甚至可以通过一些javascript库从客户端完成,只需将lat和long发送到服务器(您的选择)。

如果您仍想在模型中创建方法/设定器,我建议您在任何整合的库中获得一些灵感,并且更正式,最好,例如:Laravel Cashier(https://laravel.com/docs/5.6/billing ),在单独的逻辑单元中为模型提供额外的行为。

如果您想遵循Laravel Cashier方法,它会使用特征来应用行为: https://github.com/laravel/cashier/blob/7.0/src/Billable.php

它使用官方条带包(在您的情况下,可能是您编写的类,或任何其他类似Google Maps SDK)以及其他帮助程序和数据对象,这将使您的模型在内存和使另一个对象负责附加逻辑(更容易测试和维护),同时它也会将行为嵌入到模型中。

关于您的代码......

你不能保证设置者按照你想要的顺序执行(或者你不应该信任它总是这样做),所以,如果你想继续你已经拥有的代码,我会建议将$this->setCoordinates();移动到其他位置,例如creatingupdatingsaving等事件观察者: https://laravel.com/docs/5.6/eloquent#events

每次调用时都会评估地址,如下所示:

public function setCoordinates()
{
    $address = $this->attributes['address_line_1'] . '+' .
        $this->attributes['address_line_2'] . '+' .
        $this->attributes['address_line_3'] . '+' .
        $this->attributes['address_line_4'] . '+' .
        $this->attributes['postcode'];

    $long_lat = new LongitudeLatitude();
    $coords = $long_lat->get($address);

    $this->attributes['longitude'] = $coords['longitude'];
    $this->attributes['latitude'] = $coords['latitude'];
}

请注意,该方法是公共的,因此您可以从事件观察者调用它。

还有其他业务逻辑因素需要考虑:   - 你想给手动填充坐标的可能性吗?如果没有,您应该从$fillable数组中删除它们。   - 每次更新任何地址字段时,您真的需要评估坐标吗?然后你可能想要一个status属性来验证坐标是否是原始的(在地址字段中setters将pristine设置为false,在坐标getter中检查值是否为null或者它是不是pristine,如果是,则设置再次坐标。)