I'm trying to use Prestashop's web service to build an app for my store. For searching products, it's known that we can use
http://store_url/api/search?query=keywords&language=1
But if I search for anything, it won't give me more than 10 results. I've tried using &limit and &display. But nothing works.
If there's an alternative, please let me know.
I think you can try this way to search products:
http://store_url/api/products/?display=full&limit=2&filter[name]=[print]%
You can change display and limit.
It's from Prestashop web services doc.
Hope this helps anyone.
After much wall smashing, I've found a work around. So, the problem is in this file located at /classes/webservice,
WebserviceSpecificManagementSearch.php
Around line 87, you'll find
$results = Search::find($this->wsObject->urlFragments['language'], $this->wsObject->urlFragments['query'], 1,1, 'position', 'desc', true, false);
This the last but second argument tells the Search function that it's an ajax search. MAKING IT FALSE WILL NOT WORK.
Instead, you need to go to /classes/Search.php and find the function "find". Starting at around line 278, you'll find this:
if ($ajax)
{
$sql = 'SELECT DISTINCT p.id_product, pl.name pname, cl.name cname,
cl.link_rewrite crewrite, pl.link_rewrite prewrite '.$score.'
FROM '._DB_PREFIX_.'product p
INNER JOIN `'._DB_PREFIX_.'product_lang` pl ON (
p.`id_product` = pl.`id_product`
AND pl.`id_lang` = '.(int)$id_lang.Shop::addSqlRestrictionOnLang('pl').'
)
'.Shop::addSqlAssociation('product', 'p').'
INNER JOIN `'._DB_PREFIX_.'category_lang` cl ON (
product_shop.`id_category_default` = cl.`id_category`
AND cl.`id_lang` = '.(int)$id_lang.Shop::addSqlRestrictionOnLang('cl').'
)
WHERE p.`id_product` '.$product_pool.'
ORDER BY position DESC LIMIT 10');
return $db->executeS($sql);
}
As you can see, the results are limited by 10. So you need a way to tell the function that it's being called by the WebService. So what I did was this. It's pretty simple. Instead of
ORDER BY position DESC LIMIT 10'
use:
ORDER BY position DESC LIMIT '.(($isWS)? '10000': '10')
The variable $isWS is type Boolean. So you'll have to change the find function's declaration to this:
public static function find($id_lang, $expr, $page_number = 1, $page_size = 1, $order_by = 'position',
$order_way = 'desc', $ajax = false, $use_cookie = true, Context $context = null, $isWS = false)
Once you've done this, you can now pass in the value for $isWS from WebserviceSpecificManagementSearch. So change it to this at line 87:
$results = Search::find($this->wsObject->urlFragments['language'], $this->wsObject->urlFragments['query'], 1,1, 'position', 'asc', true, false, null, true);
Hope this helps anyone with the same problem.
Related
I am importing financial data using JSON from the web into excel, but as the source uses pagination (giving 50 results per page I need to implement pagination in order to import all the results.
The data source is JSON:
https://localbitcoins.com//sell-bitcoins-online/VES/.json?page=1
or https://localbitcoins.com//sell-bitcoins-online/VES/.json?page=2
?page=1, ?page=2, ?page=3
I use the following code to implement pagination, but receive an error:
= (page as number) as table =>
let
Source = Json.Document(Web.Contents("https://localbitcoins.com//sell-bitcoins-online/VES/.json?page=" & Number.ToText(page) )),
Data1 = Source{1}[Data],
RemoveBottom = Table.RemoveLastN(Data1,3)
in
RemoveBottom
When I envoke a parameter (1 for page 1) to test it I get the following error and I can't seem to find out why?
An error occurred in the ‘GetData’ query. Expression.
Error: We cannot convert a value of type Record to type List.
Details:
Value=Record
Type=Type
For the record, I try to include page handling using ListGenerate:
= List.Generate( ()=>
[Result= try GetData(1) otherwise null, page = 1],
each [Result] <> null,
each [Result = try GetData([page]+1) otherwise null, Page = [Page]+1],
each [Result])
What is the default way to implement pagination using Power Query in MS Excel?
I realise you asked this nearly a month ago and may have since found an answer, but will respond anyway in case it helps someone else.
This line Data1 = Source{1}[Data] doesn't make sense to me, since I think Source will be a record and you can't use {1} positional lookup syntax with records.
The code below returns 7 pages for me. You may want to check if it's getting all the pages you need/expect.
let
getPageOfData = (pageNumber as number) =>
let
options = [
Query = [page = Number.ToText(pageNumber)]
],
url = "https://localbitcoins.com/sell-bitcoins-online/VES/.json",
response = Web.Contents(url, options),
deserialised = Json.Document(response)
in deserialised,
responses = List.Generate(
() => [page = 1, response = getPageOfData(page), lastPage = null],
each [lastPage] = null or [page] <= [lastPage],
each [
page = [page] + 1,
response = getPageOfData(page),
lastPage = if [lastPage] = null then if Record.HasFields(response[pagination], "next") then null else page else [lastPage]
],
each [response]
)
in
responses
In List.Generate, my selector only picks the [response] field to keep things simple. You could drill deeper into the data either within selector itself (e.g. each [response][data][ad_list]) or create a new step/expression and use List.Transform to do so.
After a certain amount of drilling down and transforming, you might see some data like:
but that depends on what you need the data to look like (and which columns you're interested in).
By the way, I used getPageOfData in the query above, but this particular API was including the URL for the next page in its responses. So pages 2 and thereafter could have just requested the URL in the response (rather than calling getPageOfData).
Having seen this question I'm not sure why the following code for my DocDb instance isn't working:
var userApps = _docs.CreateDocumentQuery(UriFactory.CreateDocumentCollectionUri(Constants.Databases.Applications.ID, Constants.Databases.Applications.Collections.USER_APPS),
new SqlQuerySpec(#"SELECT r.appId FROM ROOT r WHERE r.userId = #userId", (#"#userId", userId).ToSqlParameters()))
.ToList()
.Select(s => (string)s.appId);
var query = _docs.CreateDocumentQuery<Document>(UriFactory.CreateDocumentCollectionUri(Constants.Databases.Applications.ID, Constants.Databases.Applications.Collections.APP_DEFINITIONS),
new SqlQuerySpec(#"SELECT r.id, r.appName FROM ROOT r WHERE r.appId IN (#userApps)", (#"#userApps", userApps.ToArray()).ToSqlParameters()),
new FeedOptions { EnableCrossPartitionQuery = true })
.AsDocumentQuery();
When I execute this, though I know the data should be returning me back a result set, it comes back empty every time.
Troubleshooting so far
Variants of .Select()
Return strings that I string.Join in to a comma-separated list.
Eg:
var userApps = string.Join(#",", _docs.CreateDocumentQuery(UriFactory.CreateDocumentCollectionUri(Constants.Databases.Applications.ID, Constants.Databases.Applications.Collections.USER_APPS),
new SqlQuerySpec(#"SELECT r.appId FROM ROOT r WHERE r.userId = #userId", (#"#userId", userId).ToSqlParameters()))
.ToList()
.Select(s => $#"'{s.appId}'");
Don't encapsulate IN parameter
Removing the () around the parameter spec in the query thinking maybe the SqlParameter spec was doing the array specification?
Eg: #"SELECT r.id, r.appName FROM ROOT r WHERE r.appId IN #userApps")
Ends up throwing "Syntax error, incorrect syntax near '#userApps'."
Validate via Azure Portal queries
Ran the (expected) SQL that this code should be running.
I get back my expected results without issue (ie: I know there is a result set for these queries as-written).
Debugger output for Query 1
AppIds are coming back from query 1.
Unsatisfactory workaround
Change query 2 to not be parameterized. Rather, inject the comma-separated list of IDs from query 1 in to it:
var userApps = string.Join(#",", _docs.CreateDocumentQuery(UriFactory.CreateDocumentCollectionUri(Constants.Databases.Applications.ID, Constants.Databases.Applications.Collections.USER_APPS),
new SqlQuerySpec(#"SELECT r.appId FROM ROOT r WHERE r.userId = #userId", (#"#userId", userId).ToSqlParameter()))
.ToList()
.Select(s => $#"'{s.appId}'"));
var query = _docs.CreateDocumentQuery<Document>(UriFactory.CreateDocumentCollectionUri(Constants.Databases.Applications.ID, Constants.Databases.Applications.Collections.APP_DEFINITIONS),
new SqlQuerySpec($#"SELECT r.id, r.appName FROM ROOT r WHERE r.appId IN ({userApps})"),
new FeedOptions { EnableCrossPartitionQuery = true })
.AsDocumentQuery();
Works perfectly but I'm not going to accept it as an answer to this problem as it goes against a couple decades-worth of SQL best practices and, frankly, shouldn't be a solution.
Here's my ToSqlParameters() extension method in case it's the culprit (this works everywhere else I've used it, though. Maybe something special is needed for arrays?):
public static SqlParameterCollection ToSqlParameters(this (string, object) parmDef) => new SqlParameterCollection(new[] { new SqlParameter(parmDef.Item1, parmDef.Item2) });
Thanks!
If you use a parameterized IN list, then it will be considered as a single value when the parameter is expanded.
For instance, for this query:
SELECT * FROM r WHERE r.item IN (#items) And #items is defined as "['val1', 'val2', 'val3']" will be interpreted as such:
SELECT * FROM r WHERE r.item IN (['val1', 'val2', 'val3'])
which basically means that you're comparing r.item to a single value that is an array of three elements (i.e. equivalent to r.item = ['val1', 'val2', 'val3']).
To compare to multiple items, you need to use a parameter for each value. Something like this: SELECT * FROM r WHERE r.item IN (#val1, #val2, #val3])
A more convenient way to write this query is to use ARRAY_CONTAINS instead and pass the array of items as a single parameter. So the above query will be written like this:
SELECT * FROM r WHERE ARRAY_CONTAINS(#items, r.item)
I have a problem with with filtering my search results by ClassNames. Below you can find a code snippet that I use, hope somebody has an idea and can help me.
SearchParameters parameters = new SearchParameters()
{
SearchFor = "support",
SearchSort = "##SCORE##",
Path = "/%",
ClassNames = "cms.faq",
CurrentCulture = "EN-US",
DefaultCulture = CMS.Helpers.CultureHelper.EnglishCulture.IetfLanguageTag,
CombineWithDefaultCulture = false,
CheckPermissions = false,
SearchInAttachments = false,
User = (CMS.Membership.UserInfo)CMS.Membership.MembershipContext.AuthenticatedUser,
SearchIndexes = index.IndexName,
StartingPosition = 0,
DisplayResults = 10,
NumberOfProcessedResults = 10,
NumberOfResults = 0,
AttachmentWhere = String.Empty,
AttachmentOrderBy = String.Empty
};
I could not find any documentation on this, but I suppose the class name should return only data of the type FAQ, but in my case it returns other data to like files, news and custom documents.
I tried also to add something like ClassNames = "+cms.faq" or ClassNames = "##cms.faq##" but had no luck with that :D
Thanks,
Classnames parameter is obsolete and it should not be used anymore. The parameter is still there because of backward compatibility, it was used to filter out search attachments when using SQL search as rocky already mentioned. If you want to filter search results by ClassNames you have to specify the classname righ in SearchFor property like this: +(apple) +classname:[cms.faq TO cms.faq] +_culture:([en-us TO en-us]
I just quickly went through the source code of v8.2 and it seems that the ClassNames parameter is only used to filter out searched attachments. I'm not sure if this is intentional or if it's a bug. I recommend you to contact Kentico support.
The correct format of the ClassNames is a semicolon separated list of page types e.g. CMS.Faq;CMS.News.
I need to use a string value as a table, in order to restore points to a player when they reconnect to a game server.
This string value is their profile ID, which never changes and I need to put data inside the string value (Kills, deaths, head shots) in order to effectively restore these points. I have had a quick look on the internet but I have not found much because I don't know what this specific thing is actually called.
To make it easier, here's what I have so far:
if (not Omega.Playertable) then
Omega.Playertable = {};
System.LogAlways("Set static record table on first connect");
end
local ID = g_gameRules.game:GetProfileId(player.id);
if (not Omega.Playertable.ID) then
table.insert(Omega.Playertable, ID);
Omega.Playertable.g_gameRules.game:GetProfileId(player.id).Kills=0;
Omega.Playertable.g_gameRules.game:GetProfileId(player.id).Deaths=0;
Omega.Playertable.g_gameRules.game:GetProfileId(player.id).Headshots=0;
else
local Kills=Omega.Playertable.g_gameRules.game:GetProfileId(player.id).Kills;
local Deaths=Omega.Playertable.g_gameRules.game:GetProfileId(player.id).Deaths;
local Headshots=Omega.Playertable.g_gameRules.game:GetProfileId(player.id).Headshots;
g_gameRules.game:SetSynchedEntityValue(playerId, 101, Kills);
g_gameRules.game:SetSynchedEntityValue(playerId, 100, Deaths);
g_gameRules.game:SetSynchedEntityValue(playerId, 102, Headshots);
end
As you can see, I've tried adding their ID into the table and adding info based on this. I cannot get the system to read the 'ID' value that I set before, so I tried adding the code that gets the ID instead, and it doesn't work. The ID is unique to each player so I cannot use a simple number system for this.
Could someone point out to me what I have done wrong here? If I manage to fix the problem, I will answer my own question on here so that it can be helpful to other users.
It seems to me that you are using the wrong table indexing syntax.
Indexing a table by a variables value in Lua is done with the [] syntax.
Furthermore, in Lua Foo.bar is syntactic sugar for Foo["bar"] both formats are interchangeable, but the . variant has limitations on which characters you can use with it. For example Foo["\n.*#%!"] is a valid table index, but you certainly can't write this: Foo.\n.*#%!
Also table.insert(t, v) inserts v at the end of the array part of the table. That means if you do this
foo = {};
foo.X = "Some value";
table.insert(foo, "X");
This is what you get
{
X = "Some value"
[1] = "X"
}
That means, if I apply this to the code you gave us, this is what you probably had in mind:
if (not Omega.Playertable) then
Omega.Playertable = {};
System.LogAlways("Set static record table on first connect");
end
local ID = g_gameRules.game:GetProfileId(player.id);
if (not Omega.Playertable[ID]) then
Omega.Playertable[ID] = {};
Omega.Playertable[ID].Kills=0;
Omega.Playertable[ID].Deaths=0;
Omega.Playertable[ID].Headshots=0;
else
local Kills = Omega.Playertable[ID].Kills;
local Deaths = Omega.Playertable[ID].Deaths;
local Headshots = Omega.Playertable[ID].Headshots;
g_gameRules.game:SetSynchedEntityValue(playerId, 101, Kills);
g_gameRules.game:SetSynchedEntityValue(playerId, 100, Deaths);
g_gameRules.game:SetSynchedEntityValue(playerId, 102, Headshots);
end
Try this:
s="35638846.12.34.45"
id,kills,deaths,headshots=s:match("(.-)%.(.-)%.(.-)%.(.-)$")
print(id,kills,deaths,headshots)
But note that these values are strings. If you're using them as numbers, use tonumber to convert them.
Weird issue I get every time I search "11.11" or "22.22" etc... No problem if I search for "aa.aa" but when I put only integers into my string, I get the following exception:
Wildcard search is supported only for non-multiple word terms
My implementation of Zend search is as below (ZF 1.11):
Zend_Search_Lucene_Search_Query_Wildcard::setMinPrefixLength(0);
Zend_Search_Lucene_Search_QueryParser::setDefaultEncoding('utf-8');
Zend_Search_Lucene_Analysis_Analyzer::setDefault(
new Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8Num_CaseInsensitive()
);
$index = Zend_Search_Lucene::open(APPLICATION_PATH.'/../var/search');
if(str_word_count($searchQuery) > 1){
$searchQuery = Zend_Search_Lucene_Search_QueryParser::escape($searchQuery);
$searchQueryArray = explode(' ', $searchQuery);
$query = new Zend_Search_Lucene_Search_Query_Phrase($searchQueryArray);
}else{
$searchQuery = Zend_Search_Lucene_Search_QueryParser::escape($searchQuery);
$query = Zend_Search_Lucene_Search_QueryParser::parse(
'title:*'.$searchQuery.'* OR
description:*'.$searchQuery.'* OR
content:*'.$searchQuery.'*'
);
}
$result = $index->find($query);
I can't really find any related issue on internet so please, let me know if you've ever been in front of the similar issue. Thank you.