I have an eloquent model, it's like this:
{
"id": 1,
"knit_factory_id": 1,
"knit_factory_name": "dignissimos",
"knit_machine_id": 9,
"knit_machine_name": "perspiciatis",
"year": 2017,
"month": 3,
"idle_info": {
"day1": 2,
"day2": 1,
"day3": 2,
"day4": 1,
"day5": 1,
"day6": 2,
"day7": 1,
"day8": 2,
"day9": 2,
"day10": 1,
"day11": 1,
"day12": 2,
"day13": 1,
"day14": 2,
"day15": 2,
"day16": 1,
"day17": 2,
"day18": 2,
"day19": 2,
"day20": 2,
"day21": 2,
"day22": 2,
"day23": 2,
"day24": 2,
"day25": 2,
"day26": 2,
"day27": 1,
"day28": 2,
"day29": 1,
"day30": 1,
"day31": 1
},
"idle_days": 19,
"continue_idle_days": 10,
"idle_capacity": 35081592.433402
}
Then, it's model:
<?php
namespace App\Model;
use App\Helpers\KnitIdleCapacityHelper;
use App\Traits\InsertCreator;
use App\Traits\InsertKnitIdleCapacityInfo;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
/**
* Class KnitIdleCapacity
* @package App\Model
*/
class KnitIdleCapacity extends Model
{
use InsertCreator, SoftDeletes, InsertKnitIdleCapacityInfo;
/**
* @var array
*/
protected $fillable = [
'knit_factory_id', 'knit_factory_name', 'knit_machine_id',
'knit_machine_name', 'year', 'month', 'idle_info',
'idle_days', 'continue_idle_days', 'idle_capacity'
];
/**
* @var array
*/
protected $hidden = ['creator_id', 'created_at', 'updated_at', 'deleted_at'];
/**
* @var array
*/
protected $casts = ['idle_info' => 'array'];
/**
*
*/
const STATUS_WORK = 1;
/**
*
*/
const STATUS_IDLE = 2;
/**
* @var array
*/
public static $status = [self::STATUS_WORK, self::STATUS_IDLE];
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function knitFactory()
{
return $this->belongsTo(CompanyAccount::class, 'knit_factory_id');
}
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function knitMachine()
{
return $this->belongsTo(KnitMachine::class, 'knit_machine_id');
}
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function creator()
{
return $this->belongsTo(Account::class, 'creator_id', 'FID');
}
/**
* @param $query
* @return mixed
*/
public function scopeWithRelationships($query)
{
return $query->with('knitFactory', 'knitMachine', 'creator');
}
/**
*
* @return KnitIdleCapacityHelper
*/
public function idleCapacity()
{
return new KnitIdleCapacityHelper($this, $this->knitMachine, $this->idle_info);
}
}
When ever I create or update the idle_info, I want to update the related fields(idle_days, continue_idle_days, idle_capacity). Due to idle_info is json, so I write a helper function to interact with it, here it is:
<?php
namespace App\Helpers;
use App\Model\KnitIdleCapacity;
use App\Model\KnitMachine;
use League\Flysystem\Exception;
/**
*
* Class KnitIdleCapacityHelper
* @package App\Helpers
*/
class KnitIdleCapacityHelper
{
/**
* @var KnitIdleCapacity
*/
protected $knitIdleCapacity;
/**
* @var KnitMachine
*/
protected $knitMachine;
/**
* @var array
*/
protected $idleInfo = [];
/**
*
* @var null
*/
protected $idleDays = null;
/**
*
* @var null
*/
protected $continueIdleDays = null;
/**
* 织机当月剩余产能
* @var null
*/
protected $idleCapacity = null;
/**
* KnitIdleCapacityHelper constructor.
* @param array $idleInfo
*/
public function __construct(KnitIdleCapacity $knitIdleCapacity, KnitMachine $knitMachine, array $idleInfo)
{
$this->knitIdleCapacity = $knitIdleCapacity;
$this->knitMachine = $knitMachine;
$this->idleInfo = $idleInfo;
}
/**
*
* @param $key
* @return mixed
*/
public function get($key)
{
return array_get($this->idleInfo, $key);
}
/**
*
* @param $key
* @param $value
* @throws Exception
*/
public function set($key, $value)
{
if (!in_array($value, KnitIdleCapacity::$status)) {
throw new Exception("{$value}");
}
$this->idleInfo[$key] = $value;
$this->persist();
}
/**
*
* @param $key
* @return bool
*/
public function has($key)
{
return array_key_exists($key, $this->idleInfo);
}
/**
*
* @return array
*/
public function all()
{
return $this->idleInfo;
}
/**
*
* @param array $attributes
* @return bool
*/
public function merge(array $attributes)
{
$this->idleInfo = array_merge(
$this->idleInfo,
array_only($attributes, array_keys($this->idleInfo))
);
return $this->persist();
}
/**
*
* @return bool
*/
public function persist()
{
$this->knitIdleCapacity->idle_info = $this->idleInfo;
return $this->knitIdleCapacity->save();
}
/**
*
* @return null
*/
public function idleDays()
{
if ($this->idleDays > 0) return $this->idleDays;
$arr = array_count_values($this->idleInfo);
$this->idleDays = $arr[KnitIdleCapacity::STATUS_IDLE];
return $this->idleDays;
}
/**
*
* @return mixed|null
*/
public function continueIdleDays()
{
if ($this->continueIdleDays > 0) return $this->continueIdleDays;
$idle = true;
$result = [];
$temp = 0;
foreach ($this->idleInfo as $capacity) {
if ($capacity === KnitIdleCapacity::STATUS_WORK) {
$idle = false;
if ($temp > 0) array_push($result, $temp);
$temp = 0;
}
if ($idle) $temp++;
$idle = true;
}
rsort($result);
$this->continueIdleDays = $result[0];
return $this->continueIdleDays;
}
/**
*
* @return mixed|null
*/
public function idleCapacity()
{
if ($this->idleCapacity) return $this->idleCapacity;
$dailyOutput = $this->knitMachine->daily_output;
$this->idleCapacity = $dailyOutput * $this->idleDays();
return $this->idleCapacity;
}
/**
*
* @return bool
*/
public function updateIdleInfo()
{
$this->knitIdleCapacity->idle_days = $this->idleDays();
$this->knitIdleCapacity->continue_idle_days = $this->continueIdleDays();
$this->knitIdleCapacity->idle_capacity = $this->idleCapacity();
return $this->knitIdleCapacity->save();
}
/**
*
* @param $key
* @return mixed
* @throws Exception
*/
public function __get($key)
{
if ($this->has($key)) {
return $this->get($key);
}
throw new Exception("{$key}");
}
}
So I write a trait to auto update the related fields, here it is:
<?php
namespace App\Traits;
trait InsertKnitIdleCapacityInfo
{
public static function bootInsertKnitIdleCapacityInfo()
{
foreach (static::getModelEvents() as $event) {
static::$event(function ($model) use ($event) {
$idleCapacity = $model->idleCapacity();
$model->idle_days = $idleCapacity->idleDays();
$model->continue_idle_days = $idleCapacity->continueIdleDays();
$model->idle_capacity = $idleCapacity->idleCapacity();
$model->save();
});
}
}
/**
*
* @return array
*/
protected static function getModelEvents()
{
if (isset(static::$recordEvents)) {
return static::$recodrdEvents;
}
return ['created', 'updated'];
}
}
At last, in the controller, I run a postman test with below data.
{
"data": [
{
"knit_factory_id": 1,
"knit_factory_name": "sed",
"knit_machine_id": 1,
"knit_machine_name": "minima",
"year": 2017,
"month": 3,
"idle_info": {
"day1": 2,
"day2": 2,
"day3": 2,
"day4": 2,
"day5": 2,
"day6": 2,
"day7": 2,
"day8": 2,
"day9": 2,
"day10": 2,
"day11": 1,
"day12": 1,
"day13": 1,
"day14": 1,
"day15": 1,
"day16": 1,
"day17": 1,
"day18": 1,
"day19": 1,
"day20": 1,
"day21": 1,
"day22": 1,
"day23": 2,
"day24": 1,
"day25": 2,
"day26": 1,
"day27": 1,
"day28": 1,
"day29": 1,
"day30": 1,
"day31": 1
}
}
]
}
the controller method:
public function store(Request $request)
{
$data = $request->get('data', []);
foreach ($data as $item) {
$knitIdleCapacity = KnitIdleCapacity::create($item);
}
return response()->json([
'message' => 'created!',
], 201);
}
Unfortunately, the program failed, but the strange thing is the above data did save in database. here is some screenshots: postman screenshot database screenshot
thank you
@Ross Wilson Thank you!
Sorry, I made a mistake. In the InsertKnitIdleCapacityInfo trait, I try to catch some KnitIdleCapacity model events, then update the KnitIdleCapacity. Obviously, this will cause a infine loop.
Here is the solution, in the trait, I turn off the model event before saving the model, after saving, turn on model events.
<?php
namespace App\Traits;
trait InsertKnitIdleCapacityInfo
{
public static function bootInsertKnitIdleCapacityInfo()
{
foreach (static::getModelEvents() as $event) {
static::$event(function ($model) use ($event) {
$idleCapacity = $model->idleCapacity();
$model->idle_days = $idleCapacity->idleDays();
$model->continue_idle_days = $idleCapacity->continueIdleDays();
$model->idle_capacity = $idleCapacity->idleCapacity();
$dispatcher = $model->getEventDispatcher();
$model->unsetEventDispatcher();
$model->save();
$model->setEventDispatcher($dispatcher);
});
}
}
/**
*
* @return array
*/
protected static function getModelEvents()
{
if (isset(static::$recordEvents)) {
return static::$recodrdEvents;
}
return ['created', 'updated'];
}
}
another solution: Or just listening the creating or updating model events, here is the code:
<?php
namespace App\Traits;
trait InsertKnitIdleCapacityInfo
{
public static function bootInsertKnitIdleCapacityInfo()
{
foreach (static::getModelEvents() as $event) {
static::$event(function ($model) use ($event) {
$idleCapacity = $model->idleCapacity();
$model->idle_days = $idleCapacity->idleDays();
$model->continue_idle_days = $idleCapacity->continueIdleDays();
$model->idle_capacity = $idleCapacity->idleCapacity();
});
}
}
/**
*
* @return array
*/
protected static function getModelEvents()
{
if (isset(static::$recordEvents)) {
return static::$recodrdEvents;
}
return ['creating', 'updating'];
}
}