per_page) || is_null($request)) { $pagination = 5; } else { $pagination = $request->per_page; } $smartblocks = SmartBlock::searchFilter($request) ->with(['creator', 'tracks', 'tracks.file', 'criteria']); if($request->has('smartblockType')) { $smartblockType = $request->get('smartblockType'); $smartblocks = ($smartblockType == 'show') ? $smartblocks->doesntHave('spotSmartblock') : $smartblocks->has('spotSmartblock'); } return $smartblocks ->paginate($pagination) ->toJson(); } /** * Method used to store a new smart block * @param Request $request * @return mixed */ public function store(Request $request) { return $this->save($request); } /** * Method used to update a smart block * @param Request $request * @param $id * @return mixed */ public function update(Request $request) { return $this->save($request); } /** * Delete a smart block, cleaning also cc_blockcontent and cc_blockcriteria * @param $id * @return int */ public function delete($id) { return SmartBlock::with(['content', 'criteria'])::destroy($id); } /** * Save a new or updated smart block, with content and criteria * @param Request $request * @param $id * @return mixed string */ public function save(Request $request) { try { $user = Auth::user();//dd($user); $request->validate([ 'name' => 'required|string', 'type' => 'required|string', 'criteria' => 'required|array' ]); $criteria = $this->createCriteria($request); $length = 0; $dbSmartBlock = SmartBlock::firstOrNew(['id' => $request->id]); $dbSmartBlock->fill([ 'name' => $request->name, 'creator_id' => $user->id, 'description' => $request->description, 'length' => $request->length, ])->save(); if ($request['smart_block_type'] === 'spot') { $dbSmartBlock->spotSmartBlock()->create(); } $this->saveCriteria($dbSmartBlock, $criteria);//ToDo: save content if (is_array($request->tracks) && count($request->tracks) > 0) { SmartBlockContent::where('block_id', '=', $dbSmartBlock->id)->delete(); foreach ($request->tracks as $key => $track) { $this->saveContent($track['file'], $dbSmartBlock->id, $key); } } return $dbSmartBlock->toJson(); } catch (\Exception $e) { Log::error($e); } } /** * Save Smart Block Criteria to database * @param SmartBlock $smartBlock * @param array $criteria * @return void */ private function saveCriteria(SmartBlock $smartBlock, Collection $criteria): void { $ids = []; foreach($criteria as $key => $criterion) { $criteriaGroup = null; if (!in_array($criterion['criteria'], ['sort', 'limit', 'repeat_tracks', 'overflow_tracks'])) { $criteriaGroup = $key; } $ids[] = SmartBlockCriteria::updateOrCreate([ 'criteria' => $criterion['criteria'], 'block_id' => $smartBlock->id, ], [ 'modifier' => $criterion['modifier'], 'value' => $criterion['value'], 'extra' => $criterion['extra'], //ToDo: understand this field 'criteriagroup' => $criteriaGroup, ]); } // dd($ids); if (!empty($ids)) { SmartBlockCriteria::whereId($smartBlock->id)->whereNotIn('id', array_column($ids, 'id'))->delete(); } } /** * Get a tracks list from a set of smart block criteria (getting them from the db * of directly passed in the request from the frontend) * @param int $block_id * @param Request $request * @return mixed json string * @throws \DateMalformedIntervalStringException */ public function getTrackList(int $block_id, Request $request) { if ($block_id === 0 && count($request->criteria) === 0) { throw new BadMethodCallException('If block_id is 0 criteria array must be passed as parameter'); } if ($block_id > 0 && count($request->criteria) === 0) { $smartBlock = SmartBlock::whereId($block_id)->first(); $criteria = $smartBlock->criteria; } else { $criteria = $this->createCriteria($request); } //dd($criteria); $files = File::smartBlockFilter($criteria)->get(); return $this->criteriaLimit($criteria, $files); } private function createCriteria(Request $request) { $criteria = new \Illuminate\Database\Eloquent\Collection(); foreach($request->criteria as $key => $criterion) { if (is_null($criterion['modifier']) || $criterion['modifier'] === '') { $criterion['modifier'] = 'N/A'; } $criteria->push(new SmartBlockCriteria($criterion)); } return $criteria; } /** * Loop through files if limit criteria is based on total length and stop * to loop when total length is reached * @param Collection $criteria * @param Collection $files * @return mixed json string * @throws \DateMalformedIntervalStringException */ private function criteriaLimit(Collection $criteria, Collection $files) { $limit = $criteria->where('criteria', 'limit')->first(); $overflow = $criteria->where('criteria', 'overflow_tracks')->first()->value; $repeat = $criteria->where('criteria', 'repeat_tracks')->first()->value; if (is_null($limit)) { return $files->toJson(); } $list = collect(); [$list, $totLengthInSeconds] = $this->recursiveAddTracks($list, $files, $limit, $repeat, $overflow); return json_encode([ 'list' => $list, 'length' => $totLengthInSeconds ]); //ToDo: add limit from instance length } private function recursiveAddTracks($list, $files, $limit, $repeat, $overflow) { $totLengthInSeconds = 0; //If limit is by time if (in_array($limit->modifier, ['hours', 'minutes'])) { //If limit is based on sum tracks length, use them as DateInterval $interval = DateInterval::createFromDateString($limit->value.' '.$limit->modifier); $totLengthFromToday = new DateTime(); $intervalFromToday = clone $totLengthFromToday; $intervalFromToday = $intervalFromToday->add($interval); foreach ($files as $file) { $fileLength = new LengthFormatter($file->length); $totLengthFromToday->add(DateInterval::createFromDateString(round($fileLength->toSeconds()).' seconds')); if ($totLengthFromToday < $intervalFromToday) { $list->push($file); $totLengthInSeconds += $fileLength->toSeconds(); } else { if ($overflow) { $list->push($file); $totLengthInSeconds += $fileLength->toSeconds(); break; } break; } } if ($repeat) { while ($totLengthFromToday < $intervalFromToday) { $newFiles = $files->shuffle(); $fileLength = new LengthFormatter($newFiles[0]->length); $totLengthFromToday->add(DateInterval::createFromDateString(round($fileLength->toSeconds()).' seconds')); if ($totLengthFromToday < $intervalFromToday) { $list->push($newFiles[0]); $totLengthInSeconds += $fileLength->toSeconds(); } else { if ($overflow) { $list->push($newFiles[0]); $totLengthInSeconds += $fileLength->toSeconds(); break; } break; } } } //If limit is by items } else { $list = collect($files); foreach ($files as $file) { $fileLength = new LengthFormatter($file->length); $totLengthInSeconds += $fileLength->toSeconds(); } if ($repeat) { while ($list->count() < $limit->value) { $newFiles = $files->shuffle(); $list->push($newFiles[0]); $fileLength = new LengthFormatter($newFiles[0]->length); $totLengthInSeconds += $fileLength->toSeconds(); } } } return array($list, $totLengthInSeconds); } /** * Save preview Smart Block Content * ToDo: understand when we need to use it * @param File $file * @param int $block_id * @param int $position * @return void */ private function saveContent(array $file, int $block_id, int $position = 0) { SmartBlockContent::create([ 'block_id' => $block_id, 'file_id' => $file['id'], 'position' => $position, 'trackoffset' => 0, //ToDo: understand this field 'cliplength' => $file['length'], 'cuein' => $file['cuein'], 'cueout' => $file['cueout'], 'fadein' => '00:00:00', //ToDo: add fadein/fadeout 'fadeout' => '00:00:00', ]); } /** * Delete a smart block, his criteria and its tracks list * @param $id * @return true */ public function destroy($id) { SmartBlockContent::where('block_id', $id)->delete(); SmartBlockCriteria::where('block_id', $id)->delete(); SmartBlock::destroy($id); return true; } }