*/ abstract class CafelClientModel implements \JsonSerializable { /** * The Api object that will handle requests and responses * * @var \App\Lib\CafelApi\Transport\ApiInterface */ protected static $apiInterface; /** * Validation rules from cafel Api * * @var array */ protected static $validationRules = []; /** * Column translations * * @var array */ protected static $columnsTranslations = []; /** * Create the Api interface * * @return void */ protected static function setUpApiInterface() { self::$apiInterface = self::$apiInterface ?: new ApiInterface(); } /** * Generate a Request from the route name * * @param string $routeName * @param array $query Params to pass on to the route. * @param array $data Http body params. * @return \App\Lib\CafelApi\Transport\Request * @throws \ErrorException If the requested route is unknown. * @throws \ErrorException If a required parameter is missing. */ public static function getResquest(string $routeName, array $query = [], array $data = []): Request { // Convert bool to integer. $query = \array_map(function ($v) { return is_bool($v) ? (int)$v : $v; }, $query); $data = \array_map(function ($v) { return is_bool($v) ? (int)$v : $v; }, $data); $routes = config('cafel.routes'); if (!isset($routes[$routeName])) { throw new \ErrorException("Unknown route $routeName from the crm"); } $route = $routes[$routeName]; $matches = []; $matchedIndex = []; \preg_match_all('/{([\w-]*)}/', $route['uri'], $matches); if (\count($matches[0])) { foreach ($matches[0] as $k => $match) { if (!isset($query[$matches[1][$k]])) { throw new \ErrorException(sprintf('Missing required parameter %s', $matches[1][$k])); } $route['uri'] = str_replace($match, $query[$matches[1][$k]], $route['uri']); $matchedIndex[$matches[1][$k]] = $query[$matches[1][$k]]; } } foreach ($matchedIndex as $key => $value) { unset($query[$key]); } if (count($query)) { $route['uri'] = sprintf('%s?%s', $route['uri'], \http_build_query($query)); } return new Request(HttpMethods::make($route['methods'][0]), $route['uri'], [], $data); } /** * Validate data row from api. * * @param array $data * @return void * @throws \Illuminate\Validation\ValidationException If data does not validate. */ public static function validateDataRow(array $data) { $validationRules = collect(static::$validationRules) /** @var string|array $rule */ ->mapWithKeys(function ($rules, string $attribute) { return [ $attribute => is_array($rules) ? collect($rules) ->map(function ($rule) { // * Handle new rule instance return \is_array($rule) ? new $rule[0]($rule[1]) : $rule; })->all() : $rules ]; })->all(); static::validateData($data, $validationRules); } /** * Validate data from api * * @param array $data * @param array $rules * @return array * @throws \Illuminate\Validation\ValidationException If data does not validate. */ protected function validateData(array $data, array $rules): array { return Validator::validate($data, $rules); } /** * Get paginated mises en places * * @param string $routeName * @param integer $page * @param integer $pageSize * @param mixed ...$args * @return array * @throws \App\Exceptions\CafelApiException If reponse status is KO, or body is not an array. */ public static function paginate(string $routeName, int $page, int $pageSize = 100, ...$args): array { self::setUpApiInterface(); $request = CafelClientModel::getResquest( $routeName, array_merge($args, ['page' => $page, 'pageSize' => $pageSize]) ); $response = self::$apiInterface->call($request); if (!\is_array($response->body)) { throw new CafelApiException('Response should have been an array'); } $out = []; foreach ($response->body as $row) { $out[] = static::translateColumns($row); } return $out; } /** * Translate row keys * * @param array $row * @return array */ protected static function translateColumns(array $row): array { foreach (static::$columnsTranslations as $cafelName => $newName) { $row = static::renameArrKey($row, $cafelName, $newName); } return $row; } /** * Rename array key * * @param array $arr * @param string $oldKey * @param string $newKey * @return array */ protected static function renameArrKey(array $arr, string $oldKey, string $newKey): array { // * Failsafe if (!isset($arr[$oldKey])) { return $arr; } $keys = array_keys($arr); $keys[array_search($oldKey, $keys)] = $newKey; $newArr = array_combine($keys, $arr); return $newArr; } /** * Fetch and store picture to a path * * @param string $folder The folder where to put the picture. * @param string $url The cafel image url. * @return string The picture path * @throws \App\Exceptions\CafelApiException If Response is not a valid array. * @throws \ErrorException If writing to temp file failed. * @throws \App\Exceptions\CafelApiImageFetchException If invalid image was given or ext could not be confirmed. * @phpcs:ignore Squiz.Commenting.FunctionCommentThrowTag.WrongNumber */ public static function fetchPicture(string $folder, string $url): string { /** @var array $query */ parse_str(\parse_url($url, \PHP_URL_QUERY), $query); $idPhoto = intval($query['idPhoto']); self::setUpApiInterface(); $request = CafelClientModel::getResquest( 'cafel.ldc.photoeleveur', ['idPhoto' => $idPhoto] ); $response = self::$apiInterface->call($request); if (!\is_array($response->body)) { throw new CafelApiException('Response should have been an array'); } // * Filter Keys using intersection \extract(\array_intersect_key($response->body, ['Ext' => '', 'Name' => '', 'Data' => ''])); return ToolboxHelper::storeImage( $folder, FileHelper::fromBase64( Str::lower($Name), Str::lower($Ext), $Data ), false ); } }