/** * Create a new DynamoDb * * @param array $settings * * @throws \InvalidArgumentException * @throws \Exception */ public function __construct($settings = []) { parent::__construct($settings); $config = ArrayUtils::clean(ArrayUtils::get($settings, 'config')); // Replace any private lookups Session::replaceLookups($config, true); // statically assign our supported version $config['version'] = '2012-08-10'; if (isset($config['key'])) { $config['credentials']['key'] = $config['key']; } if (isset($config['secret'])) { $config['credentials']['secret'] = $config['secret']; } // set up a default table schema $parameters = ArrayUtils::clean(ArrayUtils::get($config, 'parameters')); Session::replaceLookups($parameters); if (null !== ($table = ArrayUtils::get($parameters, 'default_create_table'))) { $this->defaultCreateTable = $table; } try { $this->dbConn = new DynamoDbClient($config); } catch (\Exception $ex) { throw new InternalServerErrorException("AWS DynamoDb Service Exception:\n{$ex->getMessage()}", $ex->getCode()); } }
/** * Create a new CouchDbSvc * * @param array $settings * * @throws \InvalidArgumentException * @throws \Exception */ public function __construct($settings = []) { parent::__construct($settings); $config = ArrayUtils::clean(ArrayUtils::get($settings, 'config')); Session::replaceLookups($config, true); $dsn = strval(ArrayUtils::get($config, 'dsn')); if (empty($dsn)) { $dsn = 'http://localhost:5984'; } $options = []; if (isset($config['options'])) { $options = $config['options']; } $db = isset($options['db']) ? $options['db'] : null; if (!isset($db)) { // Attempt to find db in connection string $temp = trim(strstr($dsn, '//'), '/'); $db = strstr($temp, '/'); $db = trim($db, '/'); } if (empty($db)) { $db = 'default'; } try { $this->dbConn = @new \couchClient($dsn, $db, $options); } catch (\Exception $ex) { throw new InternalServerErrorException("CouchDb Service Exception:\n{$ex->getMessage()}"); } }
/** * Create a new SqlDbSvc * * @param array $settings * * @throws \InvalidArgumentException * @throws \Exception */ public function __construct($settings = []) { parent::__construct($settings); $config = ArrayUtils::clean(ArrayUtils::get($settings, 'config')); Session::replaceLookups($config, true); $driver = isset($config['driver']) ? $config['driver'] : null; $this->dbConn = ConnectionFactory::createConnection($driver, $config); $this->dbConn->setCache($this); $this->dbConn->setExtraStore($this); $defaultSchemaOnly = ArrayUtils::getBool($config, 'default_schema_only'); $this->dbConn->setDefaultSchemaOnly($defaultSchemaOnly); switch ($this->dbConn->getDBName()) { case SqlDbDriverTypes::MYSQL: case SqlDbDriverTypes::MYSQLI: $this->dbConn->setAttribute(\PDO::ATTR_EMULATE_PREPARES, true); break; case SqlDbDriverTypes::DBLIB: $this->dbConn->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); break; } $attributes = ArrayUtils::clean(ArrayUtils::get($settings, 'attributes')); if (!empty($attributes)) { $this->dbConn->setAttributes($attributes); } }
/** * * @return array The array of cache keys associated with this service */ protected function getCacheKeys() { if (empty($this->cacheKeys)) { $this->cacheKeys = Cache::get($this->cachePrefix . 'cache_keys', []); } return ArrayUtils::clean($this->cacheKeys); }
/** * Create a new AzureTablesSvc * * @param array $settings * * @throws \InvalidArgumentException * @throws \Exception */ public function __construct($settings = array()) { parent::__construct($settings); $config = ArrayUtils::clean(ArrayUtils::get($settings, 'config')); Session::replaceLookups($config, true); $dsn = strval(ArrayUtils::get($config, 'connection_string')); if (empty($dsn)) { $name = ArrayUtils::get($config, 'account_name', ArrayUtils::get($config, 'AccountName')); if (empty($name)) { throw new \InvalidArgumentException('WindowsAzure account name can not be empty.'); } $key = ArrayUtils::get($config, 'account_key', ArrayUtils::get($config, 'AccountKey')); if (empty($key)) { throw new \InvalidArgumentException('WindowsAzure account key can not be empty.'); } $protocol = ArrayUtils::get($config, 'protocol', 'https'); $dsn = "DefaultEndpointsProtocol={$protocol};AccountName={$name};AccountKey={$key}"; } // set up a default partition key $partitionKey = ArrayUtils::get($config, static::PARTITION_KEY); if (!empty($partitionKey)) { $this->defaultPartitionKey = $partitionKey; } try { $this->dbConn = ServicesBuilder::getInstance()->createTableService($dsn); } catch (\Exception $ex) { throw new InternalServerErrorException("Windows Azure Table Service Exception:\n{$ex->getMessage()}"); } }
/** * Create a new SqlDbSvc * * @param array $settings * * @throws \InvalidArgumentException * @throws \Exception */ public function __construct($settings = []) { parent::__construct($settings); $config = ArrayUtils::clean(ArrayUtils::get($settings, 'config')); $this->cacheEnabled = ArrayUtils::getBool($config, 'cache_enabled'); $this->cacheTTL = intval(ArrayUtils::get($config, 'cache_ttl', \Config::get('df.default_cache_ttl'))); $this->cachePrefix = 'service_' . $this->id . ':'; }
/** * Create a new Script Service * * @param array $settings * * @throws \InvalidArgumentException * @throws \Exception */ public function __construct($settings = []) { parent::__construct($settings); $config = ArrayUtils::clean(ArrayUtils::get($settings, 'config')); Session::replaceLookups($config, true); if (null === ($this->content = ArrayUtils::get($config, 'content', null, true))) { throw new \InvalidArgumentException('Script content can not be empty.'); } if (null === ($this->engineConfig = ArrayUtils::get($config, 'engine', null, true))) { throw new \InvalidArgumentException('Script engine configuration can not be empty.'); } $this->scriptConfig = ArrayUtils::clean(ArrayUtils::get($config, 'config', [], true)); }
/** * {@inheritdoc} */ public function retrieveRecordsByFilter($table, $filter = null, $params = [], $extras = []) { $fields = ArrayUtils::get($extras, ApiOptions::FIELDS); $ssFilters = ArrayUtils::get($extras, 'ss_filters'); $scanProperties = [static::TABLE_INDICATOR => $table]; $fields = static::buildAttributesToGet($fields); if (!empty($fields)) { $scanProperties['AttributesToGet'] = $fields; } $parsedFilter = static::buildCriteriaArray($filter, $params, $ssFilters); if (!empty($parsedFilter)) { $scanProperties['ScanFilter'] = $parsedFilter; } $limit = intval(ArrayUtils::get($extras, ApiOptions::LIMIT)); if ($limit > 0) { $scanProperties['Limit'] = $limit; $scanProperties['Count'] = true; } $offset = intval(ArrayUtils::get($extras, ApiOptions::OFFSET)); if ($offset > 0) { $scanProperties['ExclusiveStartKey'] = $offset; $scanProperties['Count'] = true; } try { $result = $this->parent->getConnection()->scan($scanProperties); $items = ArrayUtils::clean($result['Items']); $out = []; foreach ($items as $item) { $out[] = $this->unformatAttributes($item); } $next = $this->unformatAttributes($result['LastEvaluatedKey']); $next = current($next); // todo handle more than one index here. $count = $result['Count']; $out = static::cleanRecords($out); $needMore = $count - $offset > $limit; $addCount = ArrayUtils::getBool($extras, ApiOptions::INCLUDE_COUNT); if ($addCount || $needMore) { $out['meta']['count'] = $count; if ($needMore) { $out['meta']['next'] = $next; } } return $out; } catch (\Exception $ex) { throw new InternalServerErrorException("Failed to filter records from '{$table}'.\n{$ex->getMessage()}"); } }
/** * Create a new RemoteWebService * * @param array $settings settings array * * @throws \InvalidArgumentException */ public function __construct($settings) { parent::__construct($settings); $this->autoDispatch = false; $this->query = ''; $this->cacheQuery = ''; $config = ArrayUtils::get($settings, 'config', []); $this->baseUrl = ArrayUtils::get($config, 'base_url'); // Validate url setup if (empty($this->baseUrl)) { throw new \InvalidArgumentException('Remote Web Service base url can not be empty.'); } $this->parameters = ArrayUtils::clean(ArrayUtils::get($config, 'parameters', [])); $this->headers = ArrayUtils::clean(ArrayUtils::get($config, 'headers', [])); $this->cacheEnabled = ArrayUtils::getBool($config, 'cache_enabled'); $this->cacheTTL = intval(ArrayUtils::get($config, 'cache_ttl', Config::get('df.default_cache_ttl'))); $this->cachePrefix = 'service_' . $this->id . ':'; }
/** * Create a new AwsSnsSvc * * @param array $settings * * @throws \InvalidArgumentException * @throws \Exception */ public function __construct($settings) { parent::__construct($settings); $config = ArrayUtils::clean(ArrayUtils::get($settings, 'config', [])); // Replace any private lookups Session::replaceLookups($config, true); // statically assign the our supported version $config['version'] = '2010-03-31'; if (isset($config['key'])) { $config['credentials']['key'] = $config['key']; } if (isset($config['secret'])) { $config['credentials']['secret'] = $config['secret']; } try { $this->conn = new SnsClient($config); } catch (\Exception $ex) { throw new InternalServerErrorException("AWS SNS Service Exception:\n{$ex->getMessage()}", $ex->getCode()); } $this->region = ArrayUtils::get($config, 'region'); }
/** * @param string $action * @param string $service * @param string $component * * @returns bool */ public static function getServiceFilters($action, $service, $component = null) { if (static::isSysAdmin()) { return []; } $services = ArrayUtils::clean(static::get('role.services')); $serviceAllowed = null; $serviceFound = false; $componentFound = false; $action = VerbsMask::toNumeric(static::cleanAction($action)); foreach ($services as $svcInfo) { $tempService = ArrayUtils::get($svcInfo, 'service'); if (null === ($tempVerbs = ArrayUtils::get($svcInfo, 'verb_mask'))) { // Check for old verbs array if (null !== ($temp = ArrayUtils::get($svcInfo, 'verbs'))) { $tempVerbs = VerbsMask::arrayToMask($temp); } } if (0 == strcasecmp($service, $tempService)) { $serviceFound = true; $tempComponent = ArrayUtils::get($svcInfo, 'component'); if (!empty($component)) { if (0 == strcasecmp($component, $tempComponent)) { $componentFound = true; if ($tempVerbs & $action) { $filters = ArrayUtils::get($svcInfo, 'filters'); $operator = ArrayUtils::get($svcInfo, 'filter_op', 'AND'); if (empty($filters)) { return null; } return ['filters' => $filters, 'filter_op' => $operator]; } } elseif (empty($tempComponent) || '*' == $tempComponent) { if ($tempVerbs & $action) { $filters = ArrayUtils::get($svcInfo, 'filters'); $operator = ArrayUtils::get($svcInfo, 'filter_op', 'AND'); if (empty($filters)) { return null; } $serviceAllowed = ['filters' => $filters, 'filter_op' => $operator]; } } } else { if (empty($tempComponent) || '*' == $tempComponent) { if ($tempVerbs & $action) { $filters = ArrayUtils::get($svcInfo, 'filters'); $operator = ArrayUtils::get($svcInfo, 'filter_op', 'AND'); if (empty($filters)) { return null; } $serviceAllowed = ['filters' => $filters, 'filter_op' => $operator]; } } } } } if ($componentFound) { // at least one service and component match was found, but not the right verb return null; } elseif ($serviceFound) { return $serviceAllowed; } return null; }
/** * @param string $name * @param array $event * * @return array|null * @throws InternalServerErrorException * @throws \DreamFactory\Core\Events\Exceptions\ScriptException */ protected function handleEventScript($name, &$event) { $model = EventScript::with('script_type_by_type')->whereName($name)->whereIsActive(true)->first(); if (!empty($model)) { $output = null; $result = ScriptEngineManager::runScript($model->content, $name, $model->script_type_by_type->toArray(), ArrayUtils::clean($model->config), $event, $output); // Bail on errors... if (is_array($result) && isset($result['script_result'], $result['script_result']['error'])) { throw new InternalServerErrorException($result['script_result']['error']); } if (is_array($result) && isset($result['exception'])) { throw new InternalServerErrorException(ArrayUtils::get($result, 'exception', '')); } // The script runner should return an array if (!is_array($result) || !isset($result['__tag__'])) { Log::error(' * Script did not return an array: ' . print_r($result, true)); } if (!empty($output)) { Log::info(' * Script "' . $name . '" output:' . PHP_EOL . $output . PHP_EOL); } return $result; } return null; }
/** * @param array $libraryPaths * * @throws ServiceUnavailableException */ protected static function initializeLibraryPaths($libraryPaths = null) { static::$libraryPaths = \Cache::get('scripting.library_paths', []); static::$libraries = \Cache::get('scripting.libraries', []); // Add ones from constructor $libraryPaths = ArrayUtils::clean($libraryPaths); // Application storage script path $libraryPaths[] = storage_path('scripting'); // Merge in config libraries... $libraryPaths = array_merge($libraryPaths, ArrayUtils::clean(\Config::get('df.scripting.paths', []))); // Add them to collection if valid if (is_array($libraryPaths)) { foreach ($libraryPaths as $path) { if (!in_array($path, static::$libraryPaths)) { if (!empty($path) || is_dir($path) || is_readable($path)) { static::$libraryPaths[] = $path; } else { Log::debug("Invalid scripting library path given {$path}."); } } } } \Cache::add('scripting.library_paths', static::$libraryPaths, static::DEFAULT_CACHE_TTL); if (empty(static::$libraryPaths)) { Log::debug('No scripting library paths found.'); } }
/** * @return array * @throws BadRequestException * @throws NotFoundException */ protected function handlePOST() { $data = $this->getPayloadData(); $templateName = $this->request->getParameter('template', null); $templateId = $this->request->getParameter('template_id', null); $templateData = []; if (!empty($templateName)) { $templateData = static::getTemplateDataByName($templateName); } elseif (!empty($templateId)) { $templateData = static::getTemplateDataById($templateId); } if (empty($templateData) && empty($data)) { throw new BadRequestException('No valid data in request.'); } $data = array_merge(ArrayUtils::clean(ArrayUtils::get($templateData, 'defaults', [], true)), $data); $data = array_merge($this->parameters, $templateData, $data); $text = ArrayUtils::get($data, 'body_text'); $html = ArrayUtils::get($data, 'body_html'); $count = $this->sendEmail($data, $text, $html); //Mandrill and Mailgun returns Guzzle\Message\Response object. if (!is_int($count)) { $count = 1; } return ['count' => $count]; }
/** * @param $filter_info * @param array $params * * @return null|string * @throws \DreamFactory\Core\Exceptions\InternalServerErrorException */ protected function buildQueryStringFromData($filter_info, array &$params) { $filter_info = ArrayUtils::clean($filter_info); $filters = ArrayUtils::get($filter_info, 'filters'); if (empty($filters)) { return null; } $sql = ''; $combiner = ArrayUtils::get($filter_info, 'filter_op', 'and'); foreach ($filters as $key => $filter) { if (!empty($sql)) { $sql .= " {$combiner} "; } $name = ArrayUtils::get($filter, 'name'); $op = ArrayUtils::get($filter, 'operator'); $value = ArrayUtils::get($filter, 'value'); $value = static::interpretFilterValue($value); if (empty($name) || empty($op)) { // log and bail throw new InternalServerErrorException('Invalid server-side filter configuration detected.'); } switch ($op) { case 'is null': case 'is not null': $sql .= "{$name} {$op}"; // $sql .= $this->dbConn->quoteColumnName($name) . " $op"; break; default: $paramName = ':ssf_' . $name . '_' . $key; $params[$paramName] = $value; $value = $paramName; $sql .= "{$name} {$op} {$value}"; // $sql .= $this->dbConn->quoteColumnName($name) . " $op $value"; break; } } return $sql; }
protected function getIdsInfo($table, $fields_info = null, &$requested_fields = null, $requested_types = null) { $requested_fields = static::DEFAULT_ID_FIELD; // can only be this $requested_types = ArrayUtils::clean($requested_types); $type = ArrayUtils::get($requested_types, 0, 'string'); $type = empty($type) ? 'string' : $type; return [new ColumnSchema(['name' => static::DEFAULT_ID_FIELD, 'type' => $type, 'required' => false])]; }
/** * @param bool $list_only * * @return array */ public function getSObjects($list_only = false) { $result = $this->callGuzzle('GET', 'sobjects/'); $tables = ArrayUtils::clean(ArrayUtils::get($result, 'sobjects')); if ($list_only) { $out = array(); foreach ($tables as $table) { $out[] = ArrayUtils::get($table, 'name'); } return $out; } return $tables; }
/** * {@inheritdoc} */ public function updateField($table, $field, $properties = [], $allow_delete_parts = false, $return_schema = false) { if (empty($table)) { throw new BadRequestException('Table name can not be empty.'); } $properties = ArrayUtils::clean($properties); $properties['name'] = $field; $fields = DbUtilities::validateAsArray($properties, null, true, 'Bad data format in request.'); $result = $this->dbConn->updateFields($table, $fields, true); // Any changes here should refresh cached schema $this->refreshCachedTables(); if ($return_schema) { return $this->describeField($table, $field); } return $result; }
/** * Create a new MongoDbSvc * * @param array $settings * * @throws \InvalidArgumentException * @throws \Exception */ public function __construct($settings = []) { parent::__construct($settings); static::checkExtensions(['mongo']); $config = ArrayUtils::clean(ArrayUtils::get($settings, 'config')); Session::replaceLookups($config, true); $dsn = strval(ArrayUtils::get($config, 'dsn')); if (!empty($dsn)) { if (0 != substr_compare($dsn, static::DSN_PREFIX, 0, static::DSN_PREFIX_LENGTH, true)) { $dsn = static::DSN_PREFIX . $dsn; } } $options = ArrayUtils::get($config, 'options', []); if (empty($options)) { $options = []; } $user = ArrayUtils::get($config, 'username'); $password = ArrayUtils::get($config, 'password'); // support old configuration options of user, pwd, and db in credentials directly if (!isset($options['username']) && isset($user)) { $options['username'] = $user; } if (!isset($options['password']) && isset($password)) { $options['password'] = $password; } if (!isset($options['db']) && null !== ($db = ArrayUtils::get($config, 'db', null, true))) { $options['db'] = $db; } if (!isset($db) && null === ($db = ArrayUtils::get($options, 'db', null, true))) { // Attempt to find db in connection string $db = strstr(substr($dsn, static::DSN_PREFIX_LENGTH), '/'); if (false !== ($pos = strpos($db, '?'))) { $db = substr($db, 0, $pos); } $db = trim($db, '/'); } if (empty($db)) { throw new InternalServerErrorException("No MongoDb database selected in configuration."); } $driverOptions = ArrayUtils::clean(ArrayUtils::get($config, 'driver_options')); if (null !== ($context = ArrayUtils::get($driverOptions, 'context'))) { // Automatically creates a stream from context $driverOptions['context'] = stream_context_create($context); } try { $client = @new \MongoClient($dsn, $options, $driverOptions); $this->dbConn = $client->selectDB($db); } catch (\Exception $ex) { throw new InternalServerErrorException("Unexpected MongoDb Service Exception:\n{$ex->getMessage()}"); } }
/** * @param \DreamFactory\Core\Contracts\ServiceResponseInterface $response * @param null $accepts * @param null $asFile * @param string $resource * * @return \Symfony\Component\HttpFoundation\Response * @throws \DreamFactory\Core\Exceptions\BadRequestException * @throws \DreamFactory\Core\Exceptions\NotImplementedException */ public static function sendResponse(ServiceResponseInterface $response, $accepts = null, $asFile = null, $resource = 'resource') { if (empty($accepts)) { $accepts = static::getAcceptedTypes(); } if (empty($asFile)) { $asFile = \Request::input('file'); if (true === filter_var($asFile, FILTER_VALIDATE_BOOLEAN)) { $asFile = $resource . '.json'; } if (is_string($asFile) && strpos($asFile, '.') !== false) { $format = strtolower(pathinfo($asFile, PATHINFO_EXTENSION)); if (!empty($format)) { if ($format === 'csv') { $accepts = ['text/csv']; } else { if ($format === 'xml') { $accepts = ['application/xml']; } else { if ($format === 'json') { $accepts = ['application/json']; } } } } } else { $asFile = null; } } // If no accepts header supplied or a blank is supplied for // accept header (clients like bench-rest) then use default response type from config. if (empty($accepts) || isset($accepts[0]) && empty($accepts[0])) { $accepts[] = config('df.default_response_type'); } $content = $response->getContent(); $format = $response->getContentFormat(); if (empty($content) && is_null($format)) { // No content and type specified. (File stream already handled by service) return null; } $status = $response->getStatusCode(); // In case the status code is not a valid HTTP Status code if (!in_array($status, HttpStatusCodes::getDefinedConstants())) { // Do necessary translation here. Default is Internal server error. $status = HttpStatusCodeInterface::HTTP_INTERNAL_SERVER_ERROR; } if ($content instanceof \Exception) { $status = $content instanceof RestException ? $content->getStatusCode() : ServiceResponseInterface::HTTP_INTERNAL_SERVER_ERROR; $content = self::makeExceptionContent($content); $format = DataFormats::PHP_ARRAY; } // check if the current content type is acceptable for return $contentType = $response->getContentType(); if (empty($contentType)) { $contentType = DataFormats::toMimeType($format, null); } // see if we match an accepts type, if so, go with it. $accepts = ArrayUtils::clean($accepts); if (!empty($contentType) && static::acceptedContentType($accepts, $contentType)) { return DfResponse::create($content, $status, ["Content-Type" => $contentType]); } // we don't have an acceptable content type, see if we can convert the content. $acceptsAny = false; $reformatted = false; foreach ($accepts as $acceptType) { $acceptFormat = DataFormats::fromMimeType($acceptType, null); $mimeType = false !== strpos($acceptType, ';') ? trim(strstr($acceptType, ';', true)) : $acceptType; if (is_null($acceptFormat)) { if ('*/*' === $mimeType) { $acceptsAny = true; } continue; } else { $contentType = $mimeType; } $reformatted = DataFormatter::reformatData($content, $format, $acceptFormat); } $responseHeaders = ["Content-Type" => $contentType]; if (!empty($asFile)) { $responseHeaders['Content-Disposition'] = 'attachment; filename="' . $asFile . '";'; } if ($acceptsAny) { $contentType = empty($contentType) ? DataFormats::toMimeType($format, config('df.default_response_type')) : $contentType; $responseHeaders['Content-Type'] = $contentType; return DfResponse::create($content, $status, $responseHeaders); } else { if (false !== $reformatted) { return DfResponse::create($reformatted, $status, $responseHeaders); } } throw new BadRequestException('Content in response can not be resolved to acceptable content type.'); }
/** * @param array $record * @param string|array $include List of keys to include in the output record * @param string|array $id_field Single or list of identifier fields * * @return array */ protected static function cleanRecord($record = [], $include = '*', $id_field = null) { if ('*' !== $include) { if (!empty($id_field) && !is_array($id_field)) { $id_field = array_map('trim', explode(',', trim($id_field, ','))); } $id_field = ArrayUtils::clean($id_field); if (!empty($include) && !is_array($include)) { $include = array_map('trim', explode(',', trim($include, ','))); } $include = ArrayUtils::clean($include); // make sure we always include identifier fields foreach ($id_field as $id) { if (false === array_search($id, $include)) { $include[] = $id; } } // glean desired fields from record $out = []; foreach ($include as $key) { $out[$key] = ArrayUtils::get($record, $key); } return $out; } return $record; }
/** * @param null | integer $storageServiceId * @param null | string $storageContainer * @param null | array $record * * @return \DreamFactory\Core\Contracts\ServiceResponseInterface|mixed * @throws \DreamFactory\Core\Exceptions\BadRequestException * @throws \DreamFactory\Core\Exceptions\InternalServerErrorException * @throws \Exception */ public function importAppFromPackage($storageServiceId = null, $storageContainer = null, $record = null) { $record = ArrayUtils::clean($record); $data = $this->getAppInfo(); // merge in overriding parameters from request if given $record = array_merge($data, $record); \DB::beginTransaction(); $appResults = $this->insertAppRecord($record, $storageServiceId, $storageContainer); try { $this->insertServices(); $this->insertSchemas(); $this->insertData(); $this->storeApplicationFiles($record); } catch (\Exception $ex) { //Rollback all db changes; \DB::rollBack(); throw $ex; } \DB::commit(); return $appResults; }