Skip to content

Instantly share code, notes, and snippets.

@edwardyi
Last active May 14, 2022 00:46
Show Gist options
  • Save edwardyi/e441d036fbf248b389bef4c672a1b88d to your computer and use it in GitHub Desktop.
Save edwardyi/e441d036fbf248b389bef4c672a1b88d to your computer and use it in GitHub Desktop.

Revisions

  1. edwardyi revised this gist May 14, 2022. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions ReadMe.md
    Original file line number Diff line number Diff line change
    @@ -16,13 +16,13 @@
    private $stubRepo;
    public function __construct(
    BatchStub $batchstubRouting,
    BatchStub $batchStub,
    Stub $stub,
    stubRepository $stubRepo
    ) {
    parent::__construct();
    $this->batchstubRouting = $batchstubRouting;
    $this->batchStub = $batchStub;
    $this->stub = $stub;
    $this->stubRepo = $stubRepo;
    }
  2. edwardyi revised this gist May 14, 2022. 1 changed file with 27 additions and 0 deletions.
    27 changes: 27 additions & 0 deletions ReadMe.md
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,33 @@

    ## Usage

    ### Initialize

    ```php=
    /**
    * @param App\Models\Stub $stub;
    */
    public $stub;
    /**
    * @param App\Repositories\StubRepository $StubRepo
    */
    private $stubRepo;
    public function __construct(
    BatchStub $batchstubRouting,
    Stub $stub,
    stubRepository $stubRepo
    ) {
    parent::__construct();
    $this->batchstubRouting = $batchstubRouting;
    $this->stub = $stub;
    $this->stubRepo = $stubRepo;
    }
    ```

    ### Create

    ```php=
  3. edwardyi revised this gist May 14, 2022. 1 changed file with 3 additions and 0 deletions.
    3 changes: 3 additions & 0 deletions ReadMe.md
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,6 @@

    ## Usage

    ### Create

    ```php=
  4. edwardyi revised this gist May 14, 2022. 1 changed file with 47 additions and 0 deletions.
    47 changes: 47 additions & 0 deletions ReadMe.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,47 @@
    ### Create

    ```php=
    /**
    * create
    *
    * @param array $data
    *
    * @return array
    */
    public function create($data)
    {
    return $this->stubRepo->create(
    $this->input($data, $this->batchStub->getFilteredAllowInput())
    );
    }
    ```

    ### Update

    ```php=
    /**
    * update
    *
    * @param string $id
    * @param array $data
    *
    * @return array
    */
    public function update(string $id, $data)
    {
    // get data
    $model = $this->stubRepo->find($id);
    if (!isset($model)) {
    throw new Exception("The id not found", 1);
    }
    $model->update(
    $this->input($data, $this->batchstub->getFilteredAllowInput())
    );
    return $model;
    }
    ```
  5. edwardyi renamed this gist May 14, 2022. 1 changed file with 13 additions and 13 deletions.
    26 changes: 13 additions & 13 deletions ProductRouting.php → Stub.php
    Original file line number Diff line number Diff line change
    @@ -2,38 +2,38 @@

    namespace App\Traits\Service\Batch;

    use App\Models\ProductRouting as ProductRoutingModel;
    use App\Repositories\ProductRoutingRepository;
    use App\Models\Stub as StubModel;
    use App\Repositories\StubRepository;

    /**
    * App\Traits\Service\Batch\ProductRouting
    * App\Traits\Service\Batch\Stub
    */
    class ProductRouting extends BatchBase
    class Stub extends BatchBase
    {
    /**
    * @param string $pkName;
    */
    public $pkName = 'product_routing.id';
    public $pkName = 'stub.id';

    /**
    * @param object $model;
    */
    public $model;

    /**
    * @param object $productRoutingRepo;
    * @param object $StubRepo;
    */
    public $productRoutingRepo;
    public $StubRepo;

    /**
    * construct
    */
    public function __construct(
    ProductRoutingModel $productRouting,
    ProductRoutingRepository $productRoutingRepo
    StubModel $Stub,
    StubRepository $StubRepo
    ) {
    $this->model = $productRouting;
    $this->productRoutingRepo = $productRoutingRepo;
    $this->model = $Stub;
    $this->StubRepo = $StubRepo;

    parent::__construct();
    }
    @@ -55,7 +55,7 @@ public function getAllowedUserInputColumns()
    */
    public function getModelId()
    {
    return $this->productRoutingRepo->getIdNumber($this->model);
    return $this->StubRepo->getIdNumber($this->model);
    }

    /**
    @@ -67,7 +67,7 @@ public function getModelId()
    */
    public function getExistingModelByIds(array $ids)
    {
    return $this->productRoutingRepo->whereIn('ID', $ids)->get();
    return $this->StubRepo->whereIn('ID', $ids)->get();
    }

    /**
  6. edwardyi revised this gist May 14, 2022. 1 changed file with 84 additions and 0 deletions.
    84 changes: 84 additions & 0 deletions ProductRouting.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,84 @@
    <?php

    namespace App\Traits\Service\Batch;

    use App\Models\ProductRouting as ProductRoutingModel;
    use App\Repositories\ProductRoutingRepository;

    /**
    * App\Traits\Service\Batch\ProductRouting
    */
    class ProductRouting extends BatchBase
    {
    /**
    * @param string $pkName;
    */
    public $pkName = 'product_routing.id';

    /**
    * @param object $model;
    */
    public $model;

    /**
    * @param object $productRoutingRepo;
    */
    public $productRoutingRepo;

    /**
    * construct
    */
    public function __construct(
    ProductRoutingModel $productRouting,
    ProductRoutingRepository $productRoutingRepo
    ) {
    $this->model = $productRouting;
    $this->productRoutingRepo = $productRoutingRepo;

    parent::__construct();
    }

    /**
    * getAllowedUserInputColumns
    *
    * @return array
    */
    public function getAllowedUserInputColumns()
    {
    return $this->availableFields;
    }

    /**
    * getModelId
    *
    * @return array
    */
    public function getModelId()
    {
    return $this->productRoutingRepo->getIdNumber($this->model);
    }

    /**
    * getExistingModelByIds
    *
    * @param array $ids
    *
    * @return array
    */
    public function getExistingModelByIds(array $ids)
    {
    return $this->productRoutingRepo->whereIn('ID', $ids)->get();
    }

    /**
    * insert
    *
    * @param array $data
    *
    * @return bool
    */
    public function insert(array $data)
    {
    return $this->model->insert($data);
    }
    }
  7. edwardyi revised this gist May 14, 2022. 3 changed files with 0 additions and 0 deletions.
    File renamed without changes.
    File renamed without changes.
    File renamed without changes.
  8. edwardyi created this gist May 14, 2022.
    347 changes: 347 additions & 0 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,347 @@
    <?php

    namespace App\Traits\Service\Batch;

    use App\Traits\Repository\Collectable;
    use App\Validate\UtilDate;
    use App\Exceptions\Batch\{ItemIdNotFoundException, ItemIdMissingException};
    use Exception;
    use Illuminate\Support\{Arr, Collection};


    /**
    * BatchBase
    */
    abstract class BatchBase
    {
    use Collectable;

    /**
    * @param string $pkName;
    */
    public $pkName = '';

    /**
    * @param object $existingModels;
    */
    public $existingModels;

    /**
    * @param object $dbParentItemModels;
    */
    public $dbParentItemModels;

    /**
    * @param array $availableFields;
    */
    public $availableFields;

    /**
    * getAllowedUserInputColumns
    *
    * @return array
    */
    abstract public function getAllowedUserInputColumns();

    /**
    * getModelId
    *
    * @return array
    */
    abstract public function getModelId();

    /**
    * getExistingModelByIds
    *
    * @param array $ids
    *
    * @return array
    */
    abstract public function getExistingModelByIds(array $ids);

    /**
    * construct
    */
    public function __construct()
    {
    $this->init();
    }

    /**
    * init
    *
    * @return void
    */
    public function init()
    {
    $this->availableFields = $this->model->getFillable();
    }

    /**
    * setDbParentItemModels
    *
    * @param object $dbParentItemModels
    *
    * @return object
    */
    public function setDbParentItemModels($dbParentItemModels)
    {
    // convert to collection
    if (gettype($dbParentItemModels) == 'array') {
    $dbParentItemModels = collect($dbParentItemModels);
    }
    $this->dbParentItemModels = $dbParentItemModels;
    }

    /**
    * getFilteredAllowInput
    *
    * @return array
    */
    public function getFilteredAllowInput($excludes = ['ID'])
    {
    return array_filter($this->getAllowedUserInputColumns(), function($item) use ($excludes) {
    return !in_array($item, $excludes);
    });
    }

    /**
    * validateItemUpdateByFilterOptions
    *
    * @param array $inputItems
    * @param array $filterOptions
    * @param string $keyBy = 'ID'
    *
    * @return array
    */
    public function validateItemUpdateByFilterOptions($inputItems, $filterOptions, $keyBy = 'ID')
    {
    $isUpdate = count($filterOptions) == 0;
    if ($isUpdate) {
    // validate item id not exists
    array_filter($inputItems, function($rowItem) use ($keyBy) {
    if (!array_key_exists($keyBy, $rowItem)) {
    throw new ItemIdMissingException("item明細設定有誤:".$this->pkName);
    }
    });
    }
    }

    /**
    * addValidatedDateToUserInputs
    *
    * @param array $inputs
    * @param array $dateFields
    *
    * @return array
    */
    public function addValidatedDateToUserInputs(array $inputs, array $dateFields)
    {
    $inputItems = $inputs['ITEMS'];
    foreach ($inputItems as $rowIndex => $rowItems) {
    foreach ($dateFields as $rowDate) {
    if (isset($rowItems[$rowDate])) {
    UtilDate::get($rowItems, ['field' => $rowDate, 'hint' => $rowDate.'日期格式有誤']);
    }
    }
    $inputItems[$rowIndex] = $rowItems;
    }

    $inputs['ITEMS'] = $inputItems;
    return $inputs;
    }

    /**
    * addCodeToUserInputs
    *
    * @param array $data
    *
    * @return array
    */
    public function addCodeToUserInputs(array $data)
    {
    // count how many records in database
    $dbSn = $this->model->get()->count();

    $this->setExistingModelsFromInput($data['ITEMS']);

    $existingData = $this->existingModels->toArray();

    foreach ($data['ITEMS'] as $rowIndex => $rowItem) {
    $hasId = Arr::get($rowItem, 'ID', false);
    $hasExistingData = $hasId ? Arr::get($existingData, $hasId, false) : false;

    // default using existing data or get a new serial number
    $dbSnCode = $hasExistingData ? $hasExistingData['CODE'] : SerialNumber::getSnLeftPadFromLength($rowIndex + $dbSn + 1, $this->getSerialNumberLength());

    // replace with user CODE from input
    if (array_key_exists('CODE', $rowItem)) {
    $dbSnCode = $rowItem['CODE'];
    }

    $data['ITEMS'][$rowIndex]['CODE'] = $dbSnCode;
    }

    return $data;
    }

    /**
    * setExistingModelsFromInput
    *
    * @param array $data
    *
    * @return array
    */
    public function setExistingModelsFromInput(array $rawItemInputs)
    {
    if (!$this->existingModels) {
    $collectInputs = collect($rawItemInputs);
    $ids = $collectInputs->keyBy('ID')
    ->filter(function($item, $rowKey) { return $rowKey != ""; })
    ->keys()
    ->toArray();

    // get existing data by ids
    $this->existingModels = $this->getExistingModelByIds($ids)->keyBy('ID');
    }
    }

    /**
    * getItemInputs
    *
    * @param array $rawItemInputs
    *
    * @return array
    */
    public function getItemInputs(array $rawItemInputs)
    {
    if (!method_exists($this, 'getAllowedUserInputColumns')) {
    throw new Exception("[BatchBase] getAllowedUserInputColumns not defined!");
    }

    if (!method_exists($this, 'getModelId')) {
    throw new Exception("[BatchBase] getModelId not defined!");
    }

    if (!method_exists($this, 'getExistingModelByIds')) {
    throw new Exception("[BatchBase] getExistingModelByIds not defined");
    }

    $cleans = [];
    $cleans['insert'] = [];
    $cleans['update'] = [];
    $cleans['delete'] = [];

    // get all ids for existing model
    $collectInputs = collect($rawItemInputs);

    $this->setExistingModelsFromInput($rawItemInputs);
    $existingData = $this->existingModels->toArray();

    // build format inputs by fillabe fields start
    $model = $this->model;
    $formattedInputs = [];
    foreach ($this->availableFields as $rowField) {
    $collectInputs->map(function($item, $itemIndex) use(&$formattedInputs, $rowField, $model) {
    $formattedInputs[$itemIndex][$rowField] = Arr::get($item, $rowField, $model->$rowField);
    });
    }

    unset($rawItemInputs);
    unset($collectInputs);
    // build format inputs by fillabe fields end

    foreach ($formattedInputs as $rowIndex => $rowItemInput) {
    $hasId = Arr::get($rowItemInput, 'ID', true);
    $rowId = is_null($hasId) ? $this->getModelId() : $hasId;
    // merge existing data
    $rowExistingData = Arr::get($existingData, $rowId, []);
    $isInsert = count($rowExistingData) == 0;
    $rowItemInput = array_merge($rowExistingData, $rowItemInput);

    $rowAction = ($isInsert === true) ? 'insert' : 'update';
    $cleans[$rowAction][$rowIndex] = $this->input($rowItemInput, $this->getAllowedUserInputColumns());
    $cleans[$rowAction][$rowIndex]['ID'] = $rowId;

    if ($isInsert === true) {
    $cleans[$rowAction][$rowIndex]['INSERT_USER'] = $this->getInsertUser();
    $cleans[$rowAction][$rowIndex]['INSERT_DATE'] = $this->getCurrentDateFromFormat("Y-m-d H:i:s");
    $cleans[$rowAction][$rowIndex]['MODIFY_USER'] = NULL;
    $cleans[$rowAction][$rowIndex]['MODIFY_DATE'] = NULL;
    } else {
    $cleans[$rowAction][$rowIndex]['INSERT_USER'] = $rowItemInput['INSERT_USER'];
    $cleans[$rowAction][$rowIndex]['INSERT_DATE'] = $rowItemInput['INSERT_DATE'];
    $cleans[$rowAction][$rowIndex]['MODIFY_USER'] = $this->getInsertUser();
    $cleans[$rowAction][$rowIndex]['MODIFY_DATE'] = $this->getCurrentDateFromFormat("Y-m-d H:i:s");
    }

    // sort with key
    ksort($cleans[$rowAction][$rowIndex]);
    }

    // find extra item to delete
    if ($this->dbParentItemModels) {
    $dbItemIds = $this->dbParentItemModels->keyBy('ID')->keys()->toArray();
    $inputItemIds = collect($formattedInputs)->keyBy('ID')->keys()->toArray();
    $cleans['delete'] = array_diff($dbItemIds, $inputItemIds);
    }

    return $cleans;
    }

    /**
    * updateBatch
    *
    * @param array $data
    *
    * @return array
    */
    public function updateBatch(array $data)
    {
    $result = [];
    $updateData = collect($data)->keyBy('ID');

    $this->existingModels->map(function($item, $rowIndex) use ($updateData, &$result) {
    $rowItemId = $item->ID;
    $isUpdate = $item->update($updateData[$rowItemId]);
    $result[$rowItemId] = ['status' => $isUpdate, 'item' => $item->toArray()];
    });

    return $result;
    }

    /**
    * execute
    *
    * @param array $cleanInputs
    *
    * @return array
    */
    public function execute(array $cleanInputs)
    {
    $deleteInputs = $cleanInputs['delete'];
    $insertOrUpdateInputs = array_merge($cleanInputs['insert'], $cleanInputs['update']);
    $isDeleteResult = false;
    $insertOrUpdateResult = false;

    // delete for update
    if (count($deleteInputs) > 0) {
    $isDeleteResult = $this->model->destroy($deleteInputs);
    }

    if (count($insertOrUpdateInputs) > 0) {
    $insertOrUpdateResult = $this->model::insertOnDuplicateKey($insertOrUpdateInputs, array_keys(reset($insertOrUpdateInputs)));
    }

    return [
    'is_delete' => [
    'status' => $isDeleteResult,
    'data' => $deleteInputs
    ],
    'insert_or_update' => [
    'status' => $insertOrUpdateResult,
    'data' => $insertOrUpdateInputs
    ]
    ];
    }
    }
    116 changes: 116 additions & 0 deletions gistfile2.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,116 @@
    <?php

    namespace App\Traits\Repository;

    use App\Models\Model;
    use Illuminate\Support\{Arr, Collection};

    /**
    * Collectable
    */
    trait Collectable
    {
    /**
    * keys
    */
    public function keys(Collection $collection, string $keyIndex, $isUnique = true)
    {
    $keyObj = $collection->keyBy($keyIndex)->keys();
    return $isUnique ? $keyObj->unique() : $keyObj;
    }

    /**
    * remove model append
    *
    * @param object $model
    * @param string $appendKey
    *
    * @return array
    */
    public function removeModelAppend(Model $model, string $appendKey)
    {
    $result = $model->toArray();
    unset($result[$appendKey]);
    return $result;
    }

    /**
    * removeModelAttributes
    *
    * @param Model $model
    * @param array $attributes = []
    * @param bool $isRemove = true
    *
    * @return array
    */
    public function removeModelAttributes(Model $model, array $attributes = [], $isRemove = true)
    {
    $result = $model->toArray();
    if ($isRemove == false) {
    return $result;
    }
    foreach ($attributes as $rowAttribute) {
    unset($result[$rowAttribute]);
    }

    return $result;
    }

    /**
    * clean
    *
    * @param array $data
    * @param string $field
    *
    * @return array
    */
    public function clean(&$data, $field)
    {
    if (is_null(Arr::get($data, $field))) {
    unset($data[$field]);
    }
    return $data;
    }

    /**
    * input
    *
    * @param array $data
    * @param array $modelFields
    *
    * @return array
    */
    public function input($data, $modelFields)
    {
    $input = [];

    foreach ($data as $rowKey => $rowValue) {
    if (in_array($rowKey, $modelFields)) {
    $input[$rowKey] = $rowValue;
    }
    }

    return $input;
    }

    /**
    * inputDetailByItemLength
    *
    * @param array $data
    * @param integer $legnth
    * @param array $modelFields
    *
    * @return array
    */
    public function inputDetailByItemLength(array $data,int $legnth, $modelFields)
    {
    $rowDetailInput = [];
    for($counter=0; $counter<$legnth; $counter++) {
    $rowDetailInput[$counter] = [];
    foreach ($modelFields as $rowField) {
    $rowDetailInput[$counter][$rowField] = Arr::get($data, sprintf('%s.%s', $rowField, $counter), '');
    }
    }
    return $rowDetailInput;
    }
    }
    70 changes: 70 additions & 0 deletions gistfile3.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,70 @@
    <?php

    namespace App\Validate;

    use \Illuminate\Support\Arr;
    use Carbon\Carbon;
    use \Exception;

    /**
    * UtilDate
    */
    class UtilDate
    {
    /**
    * validate
    *
    * @param string $dateValue
    * @param string $hint
    *
    * @return string
    */
    public static function validate(&$dateValue, $hint, $format='Y-m-d')
    {
    try {
    if (is_array($dateValue)) {
    foreach ($dateValue as $rowIndex => $rowDate) {
    $dateValue[$rowIndex] = Carbon::parse(trim($rowDate))->format($format);
    }
    } else {
    $dateValue = Carbon::parse(trim($dateValue))->format($format);
    }
    } catch (\Carbon\Exceptions\InvalidFormatException $e) {
    throw new Exception($hint);
    }
    return $dateValue;
    }

    /**
    * get
    *
    * @param array $dateValue
    * @param array $options
    *
    * @return string|bool
    */
    public static function get(array &$data, array $options)
    {
    $field = Arr::get($options, 'field');

    if (!array_key_exists($field, $data)) {
    return false;
    }

    try {
    $hint = Arr::get($options, 'hint');
    $format = Arr::get($options, 'format', 'Y-m-d');


    $defaultHint = is_null($hint) ? "The {$field} date is invalid" : $hint;

    if ($data[$field]) {
    $data[$field] = self::validate($data[$field], $defaultHint, $format);
    }
    } catch (Exception $e) {
    throw new Exception($e->getMessage());
    }

    return $data[$field];
    }
    }