@param        $params
@param bool   $bySource
@param string $cache_dir
@param bool   $realtime

@return array

@throws \Doctrine\DBAL\Cache\CacheException
173264
public function getCampaignSourceStatsData($params, $bySource = false, $cache_dir = __DIR__, $realtime = true)
    {
        $statBuilder = $this->getEntityManager()->getConnection()->createQueryBuilder();
        $statBuilder
            ->select(
                'ss.campaign_id',
                'ss.date_added',
                'c.is_published',
                'c.name',
                'SUM(IF(ss.type IS NULL                     , 0, 1)) AS received',
                "SUM(IF(ss.type IN ('accepted' , 'scrubbed'), 0, 1)) AS rejected",
                "SUM(IF(ss.type = 'accepted'                , 1, 0)) AS converted",
                "SUM(IF(ss.type = 'scrubbed'                , 1, 0)) AS scrubbed",
                'IFNULL(clc.cost, 0)                                 AS cost',
                'IFNULL(clr.revenue, 0)                              AS revenue'
            )
            ->from(MAUTIC_TABLE_PREFIX.'contactsource_stats', 'ss')
            ->join('ss', MAUTIC_TABLE_PREFIX.'leads', 'l', 'l.id = ss.contact_id')
            ->join('ss', MAUTIC_TABLE_PREFIX.'campaigns', 'c', 'c.id = ss.campaign_id')
            ->where('ss.type <> :invalid AND l.date_identified BETWEEN :dateFrom AND :dateTo')
            ->groupBy('ss.campaign_id')
            ->orderBy('COUNT(ss.campaign_id)', 'ASC');
        $costBuilder = $this->getEntityManager()->getConnection()->createQueryBuilder();
        $costBuilder
            ->select('lc.campaign_id', 'SUM(lc.cost) AS cost')
            ->from(MAUTIC_TABLE_PREFIX.'contact_ledger', 'lc')
            ->groupBy('lc.campaign_id');
        $costJoinCond = 'clc.campaign_id = ss.campaign_id AND ss.date_added BETWEEN :dateFrom AND :dateTo';
        $revBuilder   = $this->getEntityManager()->getConnection()->createQueryBuilder();
        $revBuilder
            ->select('lr.campaign_id', 'SUM(lr.revenue) AS revenue')
            ->from(MAUTIC_TABLE_PREFIX.'contact_ledger', 'lr')
            ->groupBy('lr.campaign_id');
        $revJoinCond = 'clr.campaign_id = ss.campaign_id AND ss.date_added BETWEEN :dateFrom AND :dateTo';
        if ($bySource) {
            $statBuilder
                ->addSelect('ss.contactsource_id', 'cs.name as source', 'cs.utm_source as utm_source')
                ->join('ss', MAUTIC_TABLE_PREFIX.'contactsource', 'cs', 'cs.id = ss.contactsource_id')
                ->addGroupBy('ss.contactsource_id, cs.utm_source');
        }
        $costBuilder
            ->addSelect('sc.contactsource_id')
            ->innerJoin(
                'lc',
                'contactsource_stats',
                'sc',
                'lc.campaign_id = sc.campaign_id AND lc.contact_id = sc.contact_id AND sc.date_added BETWEEN :dateFrom AND :dateTo'
            )
            ->addGroupBy('sc.contactsource_id');
        $costJoinCond .= ' AND clc.contactsource_id = ss.contactsource_id';
        $revBuilder
            ->addSelect('sr.contactsource_id')
            ->innerJoin(
                'lr',
                'contactsource_stats',
                'sr',
                'lr.campaign_id = sr.campaign_id AND lr.contact_id = sr.contact_id AND sr.date_added BETWEEN :dateFrom AND :dateTo'
            )
            ->addGroupBy('sr.contactsource_id');
        $revJoinCond .= ' AND clr.contactsource_id = ss.contactsource_id';

        $statBuilder
            ->leftJoin('ss', '('.$costBuilder->getSQL().')', 'clc', $costJoinCond)
            ->leftJoin('ss', '('.$revBuilder->getSQL().')', 'clr', $revJoinCond);
        $statBuilder
            ->setParameter('invalid', 'invalid')
            ->setParameter('dateFrom', $params['dateFrom'])
            ->setParameter('dateTo', $params['dateTo']);
        if (isset($params['limit']) && (0 < $params['limit'])) {
            $statBuilder->setMaxResults($params['limit']);
        }
        $results         = ['rows' => []];
        $resultsWithKeys = [];

        // setup cache
        $cache = new FilesystemCache($cache_dir.'/sql');
        $statBuilder->getConnection()->getConfiguration()->setResultCacheImpl($cache);
        $stmt       = $statBuilder->getConnection()->executeCacheQuery(
            $statBuilder->getSQL(),
            $statBuilder->getParameters(),
            $statBuilder->getParameterTypes(),
            new QueryCacheProfile(900, 'dashboard-revenue-queries', $cache)
        );
        $financials = $stmt->fetchAll();
        $stmt->closeCursor();

        // get utm_source data for leads with NO Contact Source Stat record (direct API, manually created, imports etc)
        $otherFinancials = $this->getAlternateCampaignSourceData($params, $bySource, $cache_dir, $realtime);
        $financials      = array_merge($financials, $otherFinancials);

        if (empty($financials)) {
            // no data for the time period, so return empty row values
            $financials[0] = [
                'is_published' => 0,
                'campaign_id'  => null,
                'name'         => null,
                'received'     => 0,
                'scrubbed'     => 0,
                'rejected'     => 0,
                'converted'    => 0,
                'revenue'      => 0,
                'cost'         => 0,
            ];
            if ($bySource) {
                $financials[0]['contactsource_id'] = null;
                $financials[0]['source']           = null;
                $financials[0]['utm_source']       = ''; // cant be null
            }
        }

        foreach ($financials as $financial) {
            // must be ordered as active, id, name, received, converted, revenue, cost, gm, margin, ecpm
            $financial['revenue']      = number_format(floatval($financial['revenue']), 2, '.', ',');
            $financial['cost']         = number_format(floatval($financial['cost']), 2, '.', ',');
            $financial['gross_income'] = number_format(
                (float) $financial['revenue'] - (float) $financial['cost'],
                2,
                '.',
                ','
            );

            if ($financial['gross_income'] > 0) {
                $financial['gross_margin'] = number_format(
                    100 * $financial['gross_income'] / $financial['revenue'],
                    0,
                    '.',
                    ','
                );
                $financial['ecpm']         = number_format((float) $financial['gross_income'] / 1000, 4, '.', ',');
            } else {
                $financial['gross_margin'] = 0;
                $financial['ecpm']         = 0;
            }

            $result = [
                $financial['is_published'],
                $financial['campaign_id'],
                $financial['name'],
            ];
            if ($bySource) {
                $result[] = $financial['contactsource_id'];
                $result[] = $financial['source'];
                $result[] = $financial['utm_source'];
            }
            $result[] = $financial['received'];
            $result[] = $financial['scrubbed'];
            $result[] = $financial['rejected'];
            $result[] = $financial['converted'];
            $result[] = $financial['revenue'];
            $result[] = $financial['cost'];
            $result[] = $financial['gross_income'];
            $result[] = $financial['gross_margin'];
            $result[] = $financial['ecpm'];

            $results['rows'][] = $result;
            $resultsWithKeys[] = $financial;
        }

        return true == $realtime ? $results : $resultsWithKeys;
    }
588256
function is_cached($tpl_file, $cache_id = null, $compile_id = null)
	{
		if (!$this->caching)
		return false;

		if (!isset($compile_id))
		$compile_id = $this->compile_id;

		$_params = array(
            'tpl_file' => $tpl_file,
            'cache_id' => $cache_id,
            'compile_id' => $compile_id
		);
		require_once(SMARTY_CORE_DIR . 'core.read_cache_file.php');
		return smarty_core_read_cache_file($_params, $this);
	}
555587
public function getCachedMethodParamUses()
    {
        $cache_directory = $this->config->getCacheDirectory();

        if (!$cache_directory) {
            return null;
        }

        $cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::METHOD_PARAM_USE_CACHE_NAME;

        if (!is_readable($cache_location)) {
            return null;
        }

        $cache = unserialize((string) file_get_contents($cache_location));

        if (!is_array($cache)) {
            throw new \UnexpectedValueException('The method param use cache must be an array');
        }

        return $cache;
    }
214274
private function getCampaignSourceStatsData($params)
    {
        $repo     = $this->em->getRepository(\MauticPlugin\MauticContactLedgerBundle\Entity\LedgerEntry::class);
        $statData = $repo->getCampaignSourceStatsData($params, true, $params['cacheDir'], false);

        return $statData;
    }
175612
public function query($query, array $params = null)
    {
        # If the next query should be cached then run the cache function instead
        if ($this->cacheNext) {
            $this->cacheNext = false;
            return $this->cache($query, $params);
        }

        # Ensure we have a connection to run this query on
        $this->connect();

        $this->query = $query;
        $this->params = null;
        $this->preparedQuery = false;

        if (is_array($params)) {
            $this->params = $params;
        }

        $this->quoteChars($query);
        $this->functions($query);
        $this->limit($query);
        $this->tableNames($query);
        $this->namedParams($query, $params);
        $this->paramArrays($query, $params);
        $this->convertNulls($params);

        $preparedQuery = $this->prepareQuery($query, $params);
        $this->preparedQuery = $preparedQuery;

        if ($this->output) {
            if ($this->htmlMode) {
                echo "<pre>";
            }

            echo $preparedQuery;

            if ($this->htmlMode) {
                echo "<hr>";
            } else {
                echo "\n";
            }
        }

        switch ($this->mode) {

            case "mysql":
                if (!$result = $this->server->query($preparedQuery)) {
                    $this->error();
                }
                break;

            case "postgres":
            case "redshift":
                $tmpQuery = $query;
                $query = "";

                $noParams = false;
                if ($this->mode == "redshift" && count($params) > 32767) {
                    $noParams = true;
                }

                $i = 1;
                reset($params);
                while ($pos = strpos($tmpQuery, "?")) {
                    if ($noParams) {
                        $query .= substr($tmpQuery, 0, $pos) . "'" . pg_escape_string(current($params)) . "'";
                        next($params);
                    } else {
                        $query .= substr($tmpQuery, 0, $pos) . "\$" . $i++;
                    }
                    $tmpQuery = substr($tmpQuery, $pos + 1);
                }
                $query .= $tmpQuery;

                $params = Helper::toArray($params);
                if (!$result = pg_query_params($this->server, $query, $params)) {
                    $this->error();
                }
                break;

            case "odbc":
                if (!$result = odbc_prepare($this->server, $query)) {
                    $this->error();
                }
                $params = Helper::toArray($params);
                if (!odbc_execute($result, $params)) {
                    $this->error();
                }
                break;

            case "sqlite":

                if (!is_array($params)) {
                    if (!$result = $this->server->query($preparedQuery)) {
                        $this->error();
                    }

                # If we have some parameters then we must convert them to the sqlite format
                } else {
                    $newQuery = "";
                    foreach ($params as $key => $val) {
                        $pos = strpos($query, "?");
                        $newQuery .= substr($query, 0, $pos);
                        $query = substr($query, $pos + 1);

                        $newQuery .= ":var" . $key;
                    }
                    $newQuery .= $query;

                    if (!$result = $this->server->prepare($newQuery)) {
                        $this->error();
                    }

                    foreach ($params as $key => $val) {
                        switch (gettype($val)) {

                            case "boolean":
                            case "integer":
                                $type = SQLITE3_INTEGER;
                                break;

                            case "double":
                                $type = SQLITE3_FLOAT;
                                break;

                            case "NULL":
                                if ($this->allowNulls) {
                                    $type = SQLITE3_NULL;
                                } else {
                                    $type = SQLITE3_TEXT;
                                    $val = "";
                                }
                                break;

                            default:
                                $type = SQLITE3_TEXT;
                        }

                        $result->bindValue(":var" . $key, $val, $type);
                    }

                    if (!$result = $result->execute()) {
                        $this->error();
                    }
                }
                break;

            case "mssql":
                if (!$result = mssql_query($preparedQuery, $this->server)) {
                    $this->error();
                }
                break;

            case "mssqlsrv":
                if (!$result = sqlsrv_query($this->server, $preparedQuery)) {
                    $this->error();
                }
        }

        if (!$result) {
            $this->error();
        }

        return new Result($result, $this->mode);
    }
49690
private function executeIgnoreQueryCache($parameters = null, $hydrationMode = null)
    {
        if ($hydrationMode !== null) {
            $this->setHydrationMode($hydrationMode);
        }

        if ( ! empty($parameters)) {
            $this->setParameters($parameters);
        }

        $setCacheEntry = function() {};

        if ($this->_hydrationCacheProfile !== null) {
            list($cacheKey, $realCacheKey) = $this->getHydrationCacheId();

            $queryCacheProfile = $this->getHydrationCacheProfile();
            $cache             = $queryCacheProfile->getResultCacheDriver();
            $result            = $cache->fetch($cacheKey);

            if (isset($result[$realCacheKey])) {
                return $result[$realCacheKey];
            }

            if ( ! $result) {
                $result = array();
            }

            $setCacheEntry = function($data) use ($cache, $result, $cacheKey, $realCacheKey, $queryCacheProfile) {
                $result[$realCacheKey] = $data;

                $cache->save($cacheKey, $result, $queryCacheProfile->getLifetime());
            };
        }

        $stmt = $this->_doExecute();

        if (is_numeric($stmt)) {
            $setCacheEntry($stmt);

            return $stmt;
        }

        $rsm  = $this->getResultSetMapping();
        $data = $this->_em->newHydrator($this->_hydrationMode)->hydrateAll($stmt, $rsm, $this->_hints);

        $setCacheEntry($data);

        return $data;
    }
792215
public function getByTime(Models\ByTimeParams $params)
    {
        $resource = 'bytime';
        $response = $this->sendGetRequest($resource, $params->toArray());
        $dataResponse = new Models\ByTimeData($response);
        return $dataResponse;
    }
960531
public function getTables($db = NULL, $use_cache = true): array
    {
        if (!$db) {
            $db = Configuration::getInstance()->get('db')['name'];
            if (!$db) {
                return [];
            }
        }

        if (Settings::isCacheEnabled()) {
            $cache_key = 'db_table_list_all';
            $cacher = Cacher::getInstance()->getDefaultCacher();

            if (!isset(self::$_table_list[$db])) {
                self::$_table_list[$db] = $cacher->get($cache_key);
            }
        }

        if (!isset(self::$_table_list[$db]) || !$use_cache) {
            self::$_table_list[$db] = $this->q_pairs('SHOW TABLES FROM `' . $db . '`');
        }

        if (Settings::isCacheEnabled()) {
            $cacher->set($cache_key, self::$_table_list[$db], 86400);
        }

        return self::$_table_list[$db];
    }
140105
public static function memcached($key, $class, $function, $parameters = array(), $time = MEMCACHED_TIME_DEFAULT)
    {
        $data = false;

        $memcached = self::getInstance();
        if ($memcached) {
            $key = self::$prefix . $key;


            $data = $memcached->get($key);
            if ($data) {
                return $data;
            }
            /* if( $memcached->getResultCode() != Memcached::RES_NOTSTORED ){
              return $data;
              } */
        }
        $data = call_user_func_array(array($class, $function), $parameters);

        if ($data && $memcached) {
            $memcached->set($key, $data, $time); // or die ("Failed to save data at the server");
        }
        return $data;
    }
634401
public function cache($path, $input, callable $rendered, &$success = null)
    {
        $cacheFolder = $this->getCacheDirectory();
        $destination = $path;

        if (!$this->isCacheUpToDate($destination, $input)) {
            if (!is_writable($cacheFolder)) {
                throw new RuntimeException(sprintf('Cache directory must be writable. "%s" is not.', $cacheFolder), 6);
            }

            $compiler = $this->getRenderer()->getCompiler();
            $fullPath = $compiler->locate($path) ?: $path;
            $output = $rendered($fullPath, $input);
            $importsPaths = $compiler->getImportPaths($fullPath);

            $success = $this->cacheFileContents(
                $destination,
                $output,
                $importsPaths
            );
        }

        return $destination;
    }
827371
function get($resource, $query = array(), $headers = array()) {
        $url = $this->build_url($resource, $query);
        $key = $this->buildCacheKey('get', $resource, $url, $headers, $query);
        if (($this->cacher) && ($this->cacher->has($key))) return $this->cacher->get($key);
        $result = $this->client->get($url, [
            'headers' => array_merge([
                'Authorization' => $this->getBearer()
            ], $headers)
        ])->json();
        if ($this->cacher) $this->cacher->put($key, $result);
        return $result;
    }
486793
function handleResource( $tpl, &$resourceData, $method, &$extraParameters )
    {
        $path = $resourceData['template-name'];

        $matchKeys = $this->Keys;
        if ( isset( $GLOBALS['eZDesignKeys'] ) )
        {
            $matchKeys = array_merge( $matchKeys, $GLOBALS['eZDesignKeys'] );
            unset( $GLOBALS['eZDesignKeys'] );
            $this->Keys = $matchKeys;
        }
        if ( is_array( $extraParameters ) and
             isset( $extraParameters['ezdesign:keys'] ) )
        {
            $this->mergeKeys( $matchKeys, $extraParameters['ezdesign:keys'] );
        }
        $this->KeyStack[] = $this->Keys;
        $this->Keys = $matchKeys;

        eZDebug::accumulatorStart( 'override_cache', 'Override', 'Cache load' );

        if( !isset( $GLOBALS['eZOverrideTemplateCacheMap'] ) )
        {
            $overrideCacheFile = $this->createOverrideCache();

            if ( $overrideCacheFile )
            {
                include_once( $overrideCacheFile );
            }
        }

        if ( isset( $GLOBALS['eZOverrideTemplateCacheMap'] ) )
        {
            if( isset( $GLOBALS['eZOverrideTemplateCacheMap'][md5( '/' . $path )] ) )
            {
                $cacheMap = $GLOBALS['eZOverrideTemplateCacheMap'][md5( '/' . $path )];
                if ( !is_string( $cacheMap ) and trim( $cacheMap['code'] ) )
                {
                    eval( "\$matchFile = " . $cacheMap['code'] . ";" );
                }
                else
                {
                    $matchFile = $cacheMap;
                }
                $match['file'] = $matchFile;
            }
        }
        else
        {
            $template = "/" . $path;
            $matchFileArray = eZTemplateDesignResource::overrideArray( $this->OverrideSiteAccess );

            $matchFile = $matchFileArray[$template];

            if ( isset( $matchFile['custom_match'] ) )
            {
                $matchFound = false;
                foreach ( $matchFile['custom_match'] as $customMatch )
                {
                    $matchOverride = true;
                    if ( count( $customMatch['conditions'] ) > 0 )
                    {
                        foreach ( array_keys( $customMatch['conditions'] ) as $conditionKey )
                        {
                            // Create special substring match for subtree override
                            if ( $conditionKey == 'url_alias' )
                            {
                                if ( strpos( $matchKeys['url_alias'], $customMatch['conditions'][$conditionKey] ) === 0 )
                                {
                                }
                                else
                                {
                                    $matchOverride = false;
                                }
                            }
                            else if ( isset( $matchKeys[$conditionKey] ) and
                                      isset( $customMatch['conditions'][$conditionKey] ) )
                            {
                                if ( is_array( $matchKeys[$conditionKey] ) )
                                {
                                    if ( !in_array( $customMatch['conditions'][$conditionKey], $matchKeys[$conditionKey] ) )
                                    {
                                        $matchOverride = false;
                                    }
                                }
                                else if ( $matchKeys[$conditionKey] != $customMatch['conditions'][$conditionKey] )
                                {
                                    $matchOverride = false;
                                }
                            }
                            else
                            {
                                $matchOverride = false;
                            }
                        }
                        if ( $matchOverride == true )
                        {
                            $match['file'] = $customMatch['match_file'];
                            $matchFound = true;
                            break;
                        }
                        else
                        {
                        }
                    }
                    else
                    {
                        // Default match without conditions
                        $match['file'] = $customMatch['match_file'];
                        $matchFound = true;
                    }
                }
                if ( !$matchFound )
                    $match['file'] = $matchFile['base_dir'] . $matchFile['template'];
            }
            else
            {
                $match['file'] = $matchFile['base_dir'] . $matchFile['template'];
            }
        }
        eZDebug::accumulatorStop( 'override_cache' );
        if ( isset( $match ) )
        {
            $file = $match["file"];

            $matchedKeys = array();
            $usedKeys = array();
            foreach ( $matchKeys as $matchKeyName => $matchKeyValue )
            {
                $usedKeys[$matchKeyName] = $matchKeyValue;
            }
            $extraParameters['ezdesign:used_keys'] = $usedKeys;
            $extraParameters['ezdesign:matched_keys'] = $matchedKeys;
            $tpl->setVariable( 'used', $usedKeys, 'DesignKeys' );
            $tpl->setVariable( 'matched', $matchedKeys, 'DesignKeys' );
            $resourceData['template-filename'] = $file;
            $result = eZTemplateFileResource::handleResourceData( $tpl, $this, $resourceData, $method, $extraParameters );
        }
        else
        {
            $result = false;
        }
        $this->Keys = array_pop( $this->KeyStack );
        return $result;
    }
498625
private function get_cache_key( $path, $method = 'GET', $params = array() ) {
			$canonized = $this->_api->CanonizePath( $path );
//			$exploded = explode('/', $canonized);
//			return $method . '_' . array_pop($exploded) . '_' . md5($canonized . json_encode($params));
			return strtolower( $method . ':' . $canonized ) . ( ! empty( $params ) ? '#' . md5( json_encode( $params ) ) : '' );
		}
329964
public function render($caching = false, $params = array())
	{
		if (!isset($params['template']))
		{
			if (App::isAdmin())
			{
				$db = App::get('db');
				$db->setQuery("SELECT s.`template`, e.protected FROM `#__template_styles` AS s INNER JOIN `#__extensions` AS e ON e.`element`=s.`template` WHERE s.`client_id`=0 AND s.`home`=1");
				$result = $db->loadObject();
			}
			else
			{
				$result = App::get('template');
			}

			$params['template'] = $result->template;
			if (is_dir(PATH_APP . DS . 'templates' . DS . $result->template))
			{
				$params['directory'] = PATH_APP . DS . 'templates';
			}
			else
			{
				$params['directory'] = PATH_CORE . DS . 'templates';
			}
		}

		if (!isset($params['file']))
		{
			$params['file'] = 'email.php';
		}

		if (!file_exists($params['directory'] . DS . $params['template'] . DS . $params['file']))
		{
			$params['template']  = 'system';
			$params['directory'] = PATH_CORE . DS . 'templates';
		}

		$this->_caching = $caching;

		if (!empty($this->_template))
		{
			$data = $this->_renderTemplate();
		}
		else
		{
			$this->parse($params);
			$data = $this->_renderTemplate();
		}

		if (class_exists('\Pelago\Emogrifier') && $data)
		{
			$data = str_replace('&#', '{_ANDNUM_}', $data);
			$emogrifier = new \Pelago\Emogrifier();
			$emogrifier->preserveEncoding = true;
			$emogrifier->setHtml($data);
			//$emogrifier->setCss($css);

			$data = $emogrifier->emogrify();
			$data = str_replace('{_ANDNUM_}', '&#', $data);
		}

		return $data;
	}
509899
public function render($cache = false, $params = array())
	{
		// Get the feed type
		$type = \Request::getCmd('type', 'Rss');

		// Instantiate feed renderer and set the mime encoding
		$renderer = $this->loadRenderer(($type) ? $type : 'rss');

		if (!($renderer instanceof Renderer))
		{
			\App::abort(404, \Lang::txt('Resource Not Found'));
		}

		$this->setMimeEncoding($renderer->getContentType());

		// output
		// Generate prolog
		$data  = '<?xml version="1.0" encoding="' . $this->_charset . '"?>' . "\n";
		$data .= '<!-- generator="' . $this->getGenerator() . '" -->' . "\n";

		// Generate stylesheet links
		foreach ($this->_styleSheets as $src => $attr)
		{
			$data .= '<?xml-stylesheet href="' . $src . '" type="' . $attr['mime'] . '"?>' . "\n";
		}

		// Render the feed
		$data .= $renderer->render();

		parent::render();

		return $data;
	}
1269844
public function generateCacheKeys($query, $params, $types, array $connectionParams = [])
    {
        $realCacheKey = 'query=' . $query .
            '&params=' . serialize($params) .
            '&types=' . serialize($types) .
            '&connectionParams=' . hash('sha256', serialize($connectionParams));

        // should the key be automatically generated using the inputs or is the cache key set?
        if ($this->cacheKey === null) {
            $cacheKey = sha1($realCacheKey);
        } else {
            $cacheKey = $this->cacheKey;
        }

        return [$cacheKey, $realCacheKey];
    }
1235037
public function render($cache = false, $params = array())
	{
		$xml = new \DOMDocument('1.0', 'utf-8');
		$xml->formatOutput = true;

		// The OpenSearch Namespace
		$osns = 'http://a9.com/-/spec/opensearch/1.1/';

		// Create the root element
		$elOs = $xml->createElementNS($osns, 'OpenSearchDescription');

		$elShortName = $xml->createElementNS($osns, 'ShortName');
		$elShortName->appendChild($xml->createTextNode(htmlspecialchars($this->shortName)));
		$elOs->appendChild($elShortName);

		$elDescription = $xml->createElementNS($osns, 'Description');
		$elDescription->appendChild($xml->createTextNode(htmlspecialchars($this->description)));
		$elOs->appendChild($elDescription);

		// Always set the accepted input encoding to UTF-8
		$elInputEncoding = $xml->createElementNS($osns, 'InputEncoding');
		$elInputEncoding->appendChild($xml->createTextNode('UTF-8'));
		$elOs->appendChild($elInputEncoding);

		foreach ($this->images as $image)
		{
			$elImage = $xml->createElementNS($osns, 'Image');
			$elImage->setAttribute('type', $image->type);
			$elImage->setAttribute('width', $image->width);
			$elImage->setAttribute('height', $image->height);
			$elImage->appendChild($xml->createTextNode(htmlspecialchars($image->data)));

			$elOs->appendChild($elImage);
		}

		foreach ($this->urls as $url)
		{
			$elUrl = $xml->createElementNS($osns, 'Url');
			$elUrl->setAttribute('type', $url->type);
			// Results is the defualt value so we don't need to add it
			if ($url->rel != 'results')
			{
				$elUrl->setAttribute('rel', $url->rel);
			}
			$elUrl->setAttribute('template', $url->template);

			$elOs->appendChild($elUrl);
		}

		$xml->appendChild($elOs);

		parent::render();

		return $xml->saveXML();
	}