Laravel красноречиво подсчитывает опыт работы

У меня есть настраиваемая таблица с опытом работы пользователей:

Schema::create('workplaces', function (Blueprint $table) {
    $table->increments('id');
    $table->unsignedInteger('user_id');
    $table->foreign('user_id')
          ->references('id')
          ->on('users')
          ->onDelete('cascade');
    $table->string('company')->nullable();
    $table->string('position')->nullable();
    $table->string('description')->nullable();
    $table->smallInteger('from')->nullable();
    $table->smallInteger('to')->nullable();
    $table->timestamps();
});

Вот пример данных о пользовательском опыте:

----------------------------------------------------------
| user_id | company | position | description | from | to |
----------------------------------------------------------
----------------------------------------------------------
|    1    | Google  | Designer | Lorem ipsum | 2018 |null|
----------------------------------------------------------
----------------------------------------------------------
|    1    |  Yahoo  | Designer | Lorem ipsum | 2014 |2017|
----------------------------------------------------------
----------------------------------------------------------
|    1    |Microsoft| Designer | Lorem ipsum | 2004 |2008|
----------------------------------------------------------

В этом примере пользователь с id == 1 имеет 7 лет опыта работы.

2018 - (2017 - 2014) - (2008 - 2004) = 2011

Пользователь в прошлом году работал в 2018 году, и теперь мне нужно вычесть результат из прошлого рабочего года:

2018 - 2011 = 7

Теперь текущий пользователь имеет 7-летний опыт работы.

Как я могу рассчитать пользовательский опыт работы с помощью laravel eloquent?


person Andreas Hunter    schedule 10.11.2018    source источник
comment
Что вы хотите получить на выходе? можете ли вы объяснить это, пожалуйста?   -  person Hamid Naghipour    schedule 10.11.2018
comment
@HamidNaghipour Мне нужно рассчитать опыт работы пользователей. В моем примере пользователь данных имеет 7-летний опыт работы. Как я могу рассчитать это с помощью красноречия?   -  person Andreas Hunter    schedule 10.11.2018


Ответы (2)


1) Создайте модель в папке app, где имя файла Workplace.php, со следующим содержимым:

<?php namespace App;

use Illuminate\Database\Eloquent\Model;

class Workplace extends Model 
{
    protected $table = 'workplaces';

    protected $fillable = ['user_id', 'company', 'position', 'description', 'from', 'to'];

    public $timestamps = true;


    public function user()
    {
        return $this->belongsTo('App\User');
    }

    public function experienceYears() 
    {
      $from = property_exists($this, 'from') ? $this->from : null;
      $to = property_exists($this, 'to') ? $this->to : null;
      if (is_null($from)) return 0;
      if (is_null($to)) $to = $from; // or = date('Y'); depending business logic
      return (int)$to - (int)$from;
    }

    public static function calcExperienceYearsForUser(User $user) 
    {
        $workplaces = 
            self::with('experienceYears')
                  ->whereUserId($user->id)
                  ->get(['from', 'to']);
        $years = 0;
        foreach ($workplaces AS $workplace) {
          $years+= $workplace->experienceYears;
        }
        return $years;
    }
}

2) Используйте его в действии контроллера:

$userId = 1;
$User = User::findOrFail($userId);
$yearsOfExperience = Workplace::calcExperienceYearsForUser($User);
person num8er    schedule 10.11.2018
comment
Как вы думаете, как я могу привлечь пользователей с более или менее n -летним опытом? - person Andreas Hunter; 10.11.2018
comment
@AndreasHunter для такого случая. Вы должны добавить поле experience_years в таблицу users и сделать консольную команду, которая будет периодически запускаться, выполнять вычисления и обновлять это поле. - person num8er; 10.11.2018

Я считаю, что вы должны делать такие расчеты на стороне БД. Это будет гораздо более быстрое и гибкое решение. Что, если у вас есть 1 миллион пользователей с несколькими записями об опыте и вы хотите выбрать 10 самых опытных пользователей? Делать такой расчет на стороне PHP будет крайне неэффективно.

Вот необработанный запрос (Postgres), который может выполнять основную часть работы:

SELECT SUM(COALESCE(to_year, extract(year from current_date)) - from_year) from experiences;

Если вы хотите поиграть с ним и протестировать другие случаи: http://sqlfiddle.com/#!9/c9840b/3

Другие могут сказать, что это преждевременная оптимизация, но это всего лишь одна строчка. Необработанные запросы очень эффективны и должны использоваться чаще.

person Andrius Rimkus    schedule 10.11.2018
comment
это идеальное решение, но вопрос в том, как я могу рассчитать пользовательский опыт работы с помощью laravel eloquent? Я надеюсь, что нет такого требования, чтобы показать 10 лучших пользователей (: что приведет к добавлению experience_years в таблицу users и фоновому рабочему процессу или триггеру базы данных, который будет вычислять числа и обновлять это поле - person num8er; 10.11.2018
comment
Ну, я просто хотел предложить идею. Всегда можно скрыть необработанные биты запроса в классе Model, чтобы сделать его более красноречивым. Поскольку ваш ответ технически правильный, я думаю, что нет необходимости подробно останавливаться на альтернативе. И я согласен с частью сводной таблицы/триггеров. - person Andrius Rimkus; 10.11.2018
comment
как насчет того, чтобы сделать дополнительное дополнение к вашему ответу? Потому что Андреас хочет эту функцию сейчас (: - person num8er; 10.11.2018