public function Handle_GetItemList($metadata, $request, $encoder)
    {
        // required arguments
        if (!isset($request['Paging'])) {
            CartAPI_Helpers::dieOnError($encoder, 'IncompleteRequest', 'Paging argument missing');
        }
        $sql_limit = CartAPI_Helpers::getSqlLimitFromPagingRequest($encoder, $request['Paging']);
        global $cookie;
        $id_lang = $cookie->id_lang;
        // allow to override filters before the command is executed
        if (isset($request['Filter'])) {
            $this->overrideItemListFilters($request['Filter']);
        }
        // go over the filters
        $sql_filters = array();
        $filters = CartAPI_Helpers::getDictionaryKeyAsArray($request, 'Filter');
        foreach ($filters as $filter) {
            $db_field_name_map = array('Title' => 'pl.`name`', 'CategoryId' => 'cp.`id_category`');
            $sql_filters[] = CartAPI_Helpers::getSqlFilterFromFilter($encoder, $filter, $db_field_name_map);
        }
        $sql_orderby = 'p.`id_product` desc';
        // default sort (newest items first)
        $this->overrideItemListSqlOrderBy($request, $sql_orderby);
        // complete the sql statement
        if (class_exists('Shop')) {
            $id_shop = Shop::getContextShopID(true);
            if ($id_shop !== null) {
                $sql_filters[] = 'pl.`id_shop` = ' . (int) $id_shop;
            }
        }
        $sql_filters[] = 'p.`active` = 1';
        $sql_filters[] = 'pl.`id_lang` = ' . (int) $id_lang;
        $sql_where = CartAPI_Helpers::getSqlWhereFromSqlFilters($sql_filters);
        $sql = '
			SELECT SQL_CALC_FOUND_ROWS p.`id_product`, pl.`name`, p.`active` 
			FROM `' . _DB_PREFIX_ . 'product` p 
			LEFT JOIN `' . _DB_PREFIX_ . 'category_product` cp ON cp.`id_product` = p.`id_product`
			LEFT JOIN `' . _DB_PREFIX_ . 'product_lang` pl ON p.`id_product` = pl.`id_product` 
			' . $sql_where . ' 
			GROUP BY `id_product` 
			ORDER BY ' . $sql_orderby . '
			' . $sql_limit;
        // load the products and the total element count
        $result = Db::getInstance()->ExecuteS($sql);
        $total_elements_row = Db::getInstance()->getRow('SELECT FOUND_ROWS()');
        $total_elements = intval(array_pop($total_elements_row));
        // change results before they are returned
        $this->overrideItemListResult($request, $result, $total_elements);
        // create the response
        $response = CartAPI_Helpers::createSuccessResponseWithPaging($encoder, $request['Paging'], $total_elements, CartAPI_Handlers_Helpers::getLocale());
        // add the items to the response if needed
        if (count($result) > 0) {
            $items =& $encoder->addArray($response, 'Item');
        }
        // encode each item
        foreach ($result as $row) {
            // to allow support for overrideItemListResult() to return objects instead of arrays, let's check if it's an object and fix as needed
            if (is_object($row) && $row instanceof ProductCore) {
                $arr = array();
                $arr['id_product'] = $row->id;
                $arr['name'] = $row->name;
                $row = $arr;
                // make the switch from object to array
            }
            // encode the item
            $item =& $encoder->addContainerToArray($items);
            $encoder->addNumber($item, 'Id', $row['id_product']);
            $encoder->addString($item, 'Title', $row['name']);
            $price = $this->getPriceFromProductId($row['id_product']);
            $encoder->addNumber($item, 'Price', $price);
            $referencePrice = $this->getReferencePriceFromProductId($row['id_product']);
            if ($referencePrice > $price) {
                $encoder->addNumber($item, 'ReferencePrice', $referencePrice);
            }
            $this->addThumbnailUrlFromProductId($encoder, $item, $row['id_product']);
            $this->addExtraFieldsFromProductId($metadata, $request, $encoder, $item, $row['id_product']);
        }
        // show the response
        $encoder->render($response);
    }
    public function Handle_GetCategoryList($metadata, $request, $encoder)
    {
        // required arguments
        if (!isset($request['Paging'])) {
            CartAPI_Helpers::dieOnError($encoder, 'IncompleteRequest', 'Paging argument missing');
        }
        $sql_limit = CartAPI_Helpers::getSqlLimitFromPagingRequest($encoder, $request['Paging']);
        global $cookie;
        $id_lang = $cookie->id_lang;
        // optional arguments
        $sql_filters = array();
        if (isset($request['Filter'])) {
            // change filters before the command is executed
            $this->overrideCategoryListFilters($request['Filter']);
            // TODO: support an array of filters, need to check how this works in the URL param decoder too.. may not be simple
            $db_field_name_map = array('ParentId' => 'c.`id_parent`');
            $sql_filters[] = CartAPI_Helpers::getSqlFilterFromFilter($encoder, $request['Filter'], $db_field_name_map);
        }
        $sql_orderby = '`position` ASC';
        // default sort (by db position)
        if (!property_exists('Category', 'position')) {
            $sql_orderby = '`name` ASC';
        }
        // older prestashop versions don't have the position field
        $this->overrideCategoryListSqlOrderBy($request, $sql_orderby);
        // complete the sql statement
        $sql_filters[] = 'c.`active` = 1';
        $sql_filters[] = 'cl.`id_lang` = ' . (int) $id_lang;
        $sql_where = CartAPI_Helpers::getSqlWhereFromSqlFilters($sql_filters);
        $sql = '
			SELECT SQL_CALC_FOUND_ROWS c.`id_category`, cl.`name`, c.`active` 
			FROM `' . _DB_PREFIX_ . 'category` c 
			LEFT JOIN `' . _DB_PREFIX_ . 'category_lang` cl ON c.`id_category` = cl.`id_category` 
			' . $sql_where . ' 
			GROUP BY `id_category`
			ORDER BY ' . $sql_orderby . '
			' . $sql_limit;
        // load the categories and the total element count
        $result = Db::getInstance()->ExecuteS($sql);
        $total_elements_row = Db::getInstance()->getRow('SELECT FOUND_ROWS()');
        $total_elements = intval(array_pop($total_elements_row));
        // change results before they are returned
        $this->overrideCategoryListResult($request, $result, $total_elements);
        // create the response
        $response = CartAPI_Helpers::createSuccessResponseWithPaging($encoder, $request['Paging'], $total_elements);
        // add the items to the response if needed
        if (count($result) > 0) {
            $categories =& $encoder->addArray($response, 'Category');
        }
        // encode each item
        foreach ($result as $row) {
            // encode the item
            $category =& $encoder->addContainerToArray($categories);
            $encoder->addString($category, 'Id', $row['id_category']);
            $encoder->addString($category, 'Title', $row['name']);
            // $this->addContainsItemsFromCategoryId($encoder, $category, $row['id_category']);
            $this->addContainsCategoriesFromCategoryId($encoder, $category, $row['id_category']);
            $this->addThumbnailUrlFromCategoryId($encoder, $category, $row['id_category']);
            $this->addResourcesFromCategoryId($encoder, $category, $row['id_category']);
            $this->addExtraFieldsFromCategoryId($metadata, $request, $encoder, $category, $row['id_category']);
        }
        // show the response
        $encoder->render($response);
    }