How can i apply cell format dynamically by columns name? - php

good day, my current problems here is to apply date and decimal format based on columns name.
`
//Date Format
new \Google\Service\Sheets\Request([
"repeatCell" => [
"range" => [
"sheetId" => $sheet_id,
"startColumnIndex" => 1,
"endColumnIndex" => 3,
],
"cell" => [
"userEnteredFormat" => [
"numberFormat" => [
"type" => "DATE",
"pattern" => "dd-mm-yyyy"
]
]
],
"fields" => "userEnteredFormat.numberFormat",
],
]),
//Decimal Format
new \Google\Service\Sheets\Request([
"repeatCell" => [
"range" => [
"sheetId" => $sheet_id,
"startColumnIndex" => 2,
"endColumnIndex" => (sizeof($this->dataCols->all())),
],
"cell" => [
"userEnteredFormat" => [
"numberFormat" => [
"type" => "NUMBER",
"pattern" => "#,##0.00"
]
]
],
"fields" => "userEnteredFormat.numberFormat",
],
]),
`
I already figure it out based on column range. My real question is which part do i need to modified to apply cell format based on column name? Thank you.
The sample:
This is date columns.
This is Amount column.
i have alots of columns name that goes by default datatype.Currently, i set the format based on range, for examples like setIndexColumns =>0, endIndexColumns =>3, . How do i set the datatype format by columns name? for examples, if the columns name Doc. Date, the whole column or the data will be shown as date format. if the columns name Amount(MYR), the whole column or data will be shown as decimal format.

I believe your goal is as follows.
You want to set the number format to the columns by searching the column title. The request body of the number format is shown in your script.
In your Spreadsheet, the header row is row 3. And, you want to set the number format from row 3 to the last row.
You want to achieve this using googleapis for PHP.
You have already been able to get and put values to Google Spreadsheet using Sheets API.
In this case, I thought that the following flow is required to be done.
Retrieve the header row (In your situation, it's row 3.).
Create the request body by searching the column using the header title.
Request Sheets API using the created request body.
When this flow is reflected in the sample script, it becomes as follows.
Sample script:
$service = ###; // Please use your client.
$spreadsheet_id = "###"; // please set Spreadsheet ID.
$sheet_name = "Sheet1"; // Please set the sheet name.
$sheet_id = "###"; // Please set the sheet ID of the sheet name.
// Object for searching the header title. This is from your showing script.
$obj = [
"Doc. Date" => ["numberFormat" => ["type" => "DATE", "pattern" => "dd-mm-yyyy"]],
"Amount (MYR)" => ["numberFormat" => ["type" => "NUMBER", "pattern" => "#,##0.00"]]
];
// Retrieve the header title.
$res1 = $service->spreadsheets_values->get($spreadsheet_id, "'" . $sheet_name . "'!A3:3");
$header = $res1["values"][0];
// Create a request body for batchUpdate.
$requests = [];
foreach ($header as $i => $h) {
if (array_key_exists($h, $obj)) {
array_push($requests,
new \Google\Service\Sheets\Request([
"repeatCell" => [
"range" => [
"sheetId" => $sheet_id,
"startColumnIndex" => $i,
"endColumnIndex" => $i + 1,
"startRowIndex" => 3,
],
"cell" => ["userEnteredFormat" => $obj[$h]],
"fields" => "userEnteredFormat.numberFormat",
],
]),
);
};
}
// Request Sheets API using the created request body.
if (count($requests) > 0) {
$batchUpdateCellFormatRequest = new \Google\Service\Sheets\BatchUpdateSpreadsheetRequest(["requests" => $requests]);
$service->spreadsheets->batchUpdate($spreadsheet_id, $batchUpdateCellFormatRequest);
};
When this script is run, the header title is retrieved from row 3, and create a request body using the header title and object. And, request Sheets API using the request body.
Note:
If your actual header titles are different from $obj, please modify them for your actual header title.
References:
Method: spreadsheets.values.get
Method: spreadsheets.batchUpdate

Related

Zammad API: Create ticket with tag

For those who don't want to read the whole question:
I'm looking for the index in the API-Request (Zammad) to set a tag while creating a ticket.
Details:
I'm using PHP to make an API-Request to my server where Zammad is installed. The following shows the data i sent via curl:
json_encode([
"title" => $title,
"group_id" => 2,
"priority_id" => 2,
"category" => 'Some Category',
"state_id" => 1,
"type" => "Some Type",
"customer" => $userID,
"article" => [
"body" => $htmlBody,
"type" => "note",
"content_type" => "text/html",
],
"tag_list" => [ // <-- The question is about this segment
"The tag i want to add",
],
]);
After converting the data to JSON, im sending it via POST to http://<myServerIP>/api/v1/tickets
What I've tried so far:
I tried guessing the index of the tag at which i failed.
The first full example is shown above.
Secondly:
...
"tag_id" => 9, // I've check its the actual ID of the tag i want to add
And Finally:
...
"tag" => "The tag i want to add",
Needless to say that i didn't succeed. Sometimes i get an error id (im assuming its because the index doesn't exist [who would have thought that? :)]), sometimes i get nothing and Zammad just creates the ticket without the tag. What do i mean when i say sometimes? I refer my tries specified above.
What I've also tried:
Searching for some answer on the web. The thing that comes close to what i want is this. But i would rather create the ticket with the tag instead of making another request just to add the tag.
I've looked inside the code, its written in ruby. The index is 'tags' and needs to be sperated by ,.
Basicly:
json_encode([
"title" => $title,
"group_id" => 2,
"priority_id" => 2,
"category" => 'Some Category',
"state_id" => 1,
"type" => "Some Type",
"customer" => $userID,
"article" => [
"body" => $htmlBody,
"type" => "note",
"content_type" => "text/html",
],
"tags" => "tag1,tag2,tag3", // or simply "tags" => "tag1"
]);
It might help someone in the future ...

(Elasticsearch) Convert Unix formatted data into timestamp (without changing the mappings)

We're executing an Elasticsearch query like this using PHP API:
$params = [
//please ignore the variables below,
//we made it in dynamic parameter-based in our function,
//that's why they're variables
'index' => $ourIndex,
'type' => $ourType,
'from' => $from,
'size' => $page_size,
'body' => [
"query" => [
'bool' => [
'must' => [
[
"query_string" => [
"default_field" => $content,
"query" => "$keywords"
]
],
[
"range" => [
"#timestamp" => [
"from" => $parseParams['pub_date_start'],
"to" => $parseParams['pub_date_end'],
'format' => "yy-MMM-dd'T'HH:mm:ss.SSS'Z'",
]
]
]
]
]
]
]
];
The query above works with our #timestamp field because its type is on date
"#timestamp" : {
"type" : "date"
}
And a sample value is like this:
"#timestamp" : "2019-06-17T16:53:55.778Z"
However, we want to target our pub_date field in our index, and in its mapping, the field has a type of long
"pub_date" : {
"type" : "long"
},
so it has this kind of values when we're displaying the documents:
"pub_date" : 1510358400
When we changed the query above to target instead of #timestamp to pub_date, it now displays an error like this:
Tried Solutions
I tried to add an additional format epoch_millis in the format property:
[
"range" => [
"pub_date" => [
"from" => $parseParams['pub_date_start'],
"to" => $parseParams['pub_date_end'],
'format' => "yyyy-MM-dd||yy-MMM-dd'T'HH:mm:ss.SSS'Z'||epoch_millis",
]
]
]
But still fails
Main Question
I feel that the Unix formatted values cant be recognized by the range query of Elasticsearch so that's why the query fails. Is there a work-around for this without changing the MAPPINGS of the index?
Because the other possible solutions suggested to change the mapping, but we already have around 25 million documents in the index, so we thought formatting it in PHP would be a nicer approach
Since the field is of type long and stores the unix timestamp, simply convert the date in $parseParams['pub_date_start'] and $parseParams['pub_date_end'] to unix timestamp using strtotime. Update the range query as below:
"range" => [
"pub_date" => [
"from" => strtotime($parseParams['pub_date_start']),
"to" => strtotime($parseParams['pub_date_end']),
]
]

How can i set a dynamic date for a JSON value?

Im trying to set a POST request to a file in my website with some data in JSON. There is a value response that needs to be a dynamic date so when the request is made the current date is saved in a custom field. How can i set up the code under "value" so the date is generated?
Have tried things like "variable":{ new Date(), } but can't make it work since always ends displaying the code and not a date, or the code is not validated if i add [ or { , etc.
{
"version": "v2",
"content": {
"messages": [],
"actions": [{
"action": "set_field_value",
"field_name": "bday_reg_date",
"value": "2019-06-22"
}, {
"action": "set_field_value",
"field_name": "bday_exp_date",
"value": "2019-06-29"
}
That's the code im basing mine. Everytime i access the file (apparently a .php file), a new date is generated on "value", that date is send and to a custom field called reg_date on another platform. What should be the correct way to get that dynamic value?
Thanks.
If your are trying to create a new json object in PHP you have to create an array first then use the json_encode($arr) function to convert it to json.
https://www.php.net/manual/en/function.json-encode.php
IE:
<?php
$dateNow = new DateTime('now');
$dateNextWeek = new DateTime('now');
$dateNextWeek->modify('+1 week');
$arr = [
'version' => 'v2',
'content' => [
'messages' => [],
'actions' => [
[
'action' => 'set_field_value',
'field_name' => 'bday_reg_date',
'value' => $dateNow->format('d-m-Y'),
],
[
'action' => 'set_field_value',
'field_name' => 'bday_reg_date',
'value' => $dateNextWeek->format('d-m-Y'),
],
]
]
];
return json_encode($arr);

Using elasticsearch, how to create an index for a document that contains an array, and append to that array in the future

In my example code I am using the php client library, but it should be understood by anyone familiar with elasticsearch.
I'm using elasticsearch to create an index where each document contains an array of nGram indexed authors. Initially, the document will have a single author, but as time progresses, more authors will be appended to the array. Ideally, a search could be executed by an author's name, and if any of the authors in the array get matched, the document will be found.
I have been trying to use the documentation here for appending to the array and here for using the array type - but I have not had success getting this working.
First, I want to create an index for documents, with a title, array of authors, and an array of comments.
$client = new Client();
$params = [
'index' => 'document',
'body' => [
'settings' => [
// Simple settings for now, single shard
'number_of_shards' => 1,
'number_of_replicas' => 0,
'analysis' => [
'filter' => [
'shingle' => [
'type' => 'shingle'
]
],
'analyzer' => [
'my_ngram_analyzer' => [
'tokenizer' => 'my_ngram_tokenizer',
'filter' => 'lowercase',
]
],
// Allow searching for partial names with nGram
'tokenizer' => [
'my_ngram_tokenizer' => [
'type' => 'nGram',
'min_gram' => 1,
'max_gram' => 15,
'token_chars' => ['letter', 'digit']
]
]
]
],
'mappings' => [
'_default_' => [
'properties' => [
'document_id' => [
'type' => 'string',
'index' => 'not_analyzed',
],
// The name, email, or other info related to the person
'title' => [
'type' => 'string',
'analyzer' => 'my_ngram_analyzer',
'term_vector' => 'yes',
'copy_to' => 'combined'
],
'authors' => [
'type' => 'list',
'analyzer' => 'my_ngram_analyzer',
'term_vector' => 'yes',
'copy_to' => 'combined'
],
'comments' => [
'type' => 'list',
'analyzer' => 'my_ngram_analyzer',
'term_vector' => 'yes',
'copy_to' => 'combined'
],
]
],
]
]
];
// Create index `person` with ngram indexing
$client->indices()->create($params);
Off the get go, I can't even create the index due to this error:
{"error":"MapperParsingException[mapping [_default_]]; nested: MapperParsingException[No handler for type [list] declared on field [authors]]; ","status":400}
HAD this gone successfully though, I would plan to create an index, starting with empty arrays for authors and title, something like this:
$client = new Client();
$params = array();
$params['body'] = array('document_id' => 'id_here', 'title' => 'my_title', 'authors' => [], 'comments' => []);
$params['index'] = 'document';
$params['type'] = 'example_type';
$params['id'] = 'id_here';
$ret = $client->index($params);
return $ret;
This seems like it should work if I had the desired index to add this structure of information to, but what concerns me would be appending something to the array using update. For example,
$client = new Client();
$params = array();
//$params['body'] = array('person_id' => $person_id, 'emails' => [$email]);
$params['index'] = 'document';
$params['type'] = 'example_type';
$params['id'] = 'id_here';
$params['script'] = 'NO IDEA WHAT THIS SCRIPT SHOULD BE TO APPEND TO THE ARRAY';
$ret = $client->update($params);
return $ret;
}
I am not sure how I would go about actually appending a thing to the array and making sure it's indexed.
Finally, another thing that confuses me is how I could search based on any author in the array. Ideally I could do something like this:
But I'm not 100% whether it will work. Maybe there is something fundemental about elasticsearch that I am not understanding. I am completely new to so any resources that will get me to a point where these little details don't hang me up would be appreciated.
Also, any direct advice on how to use elasticsearch to solve these problems would be appreciated.
Sorry for the big wall of text, to recap, I am looking for advice on how to
Create an index that supports nGram analysis on all elements of an array
Updating that index to append to the array
Searching for the now-updated index.
Thanks for any help
EDIT: thanks to #astax, I am now able to create the index and append to the value as a string. HOWEVER, there are two problems with this:
the array is stored as a string value, so a script like
$params['script'] = 'ctx._source.authors += [\'hello\']';
actually appends a STRING with [] rather than an array containing a value.
the value inputted does not appear to be ngram analyzed, so a search like this:
$client = new Client();
$searchParams['index'] = 'document';
$searchParams['type'] = 'example_type';
$searchParams['body']['query']['match']['_all'] = 'hello';
$queryResponse = $client->search($searchParams);
print_r($queryResponse); // SUCCESS
will find the new value but a search like this:
$client = new Client();
$searchParams['index'] = 'document';
$searchParams['type'] = 'example_type';
$searchParams['body']['query']['match']['_all'] = 'hel';
$queryResponse = $client->search($searchParams);
print_r($queryResponse); // NO RESULTS
does not
There is no type "list" in elasticsearch. But you can use "string" field type and store array of values.
....
'comments' => [
'type' => 'string',
'analyzer' => 'my_ngram_analyzer',
'term_vector' => 'yes',
'copy_to' => 'combined'
],
....
And index a document this way:
....
$params['body'] = array(
'document_id' => 'id_here',
'title' => 'my_title',
'authors' => [],
'comments' => ['comment1', 'comment2']);
....
As for the script for apending an element to array, this answer may help you - Elasticsearch upserting and appending to array
However, do you really need to update the document? It might be easier to just reindex it as this is exactly what Elasticsearch does internally. It reads the "_source" property, does the required modification and reindexes it. BTW, this means that "_source" must be enabled and all properties of the document should be included into it.
You also may consider storing comments and authors (as I understand these are authors of comments, not the document authors) as child document in ES and using "has_child" filter.
I can't really give you specific solution, but strongly recommend installing Marvel plugin for ElasticSearch and use its "sense" tool to check how your overall process works step by step.
So check if your tokenizer is properly configured by running tests as described at http://www.elastic.co/guide/en/elasticsearch/reference/1.4/indices-analyze.html.
Then check if your update script is doing what you expect by retrieving the document by running GET /document/example_type/some_existing_id
The authors and comments should be arrays, but not strings.
Finally perform the search:
GET /document/_search
{
'query' : {
'match': { '_all': 'hel' }
}
}
If you're building the query yourself rather than getting it from the user, you may use query_string with placeholders:
GET /document/_search
{
'query' : {
'query_string': {
'fields': '_all',
'query': 'hel*'
}
}
}

Store and retrieve nested JSON in DynamoDB with PHP SDK

I have created the following table in DynamoDB:
Field1: messageId / Type: String / Example value: 4873dd28-190a-4363-8299-403c535e160f
Field2: microtime / Type: Number / Example value: 14143960092414
Field3: data / Type: nested JSON-Array / Example value: {"foo":"bar","other":{"nested":1}}
I am performing the following request using PHP SDK for DynamoDB to create an entry
$raw = '{"foo":"bar","other":{"nested":1}}';
$result = $client->putItem(array(
'TableName' => 'requests2',
'Item' => array(
'messageId' => array('S' => '4873dd28-190a-4363-8299-403c535e160f'),
'microtime' => array('N' => microtime(true)*10000),
'data' => array('S' => $raw),
)
));
I want then to query the table and filter using variables within the JSON-array data field. Is my above solution to entering the data the right approach? The JSON-array gets stored as string, as to my understanding. Do we need another datatype? Basically, I can already query the table like below to retrieve messages that were added within the last minute:
$iterator = $client->getIterator('Query', array(
'TableName' => 'requests2',
'KeyConditions' => array(
'messageId' => array(
'AttributeValueList' => array(
array('S' => '4873dd28-190a-4363-8299-403c535e160f')
),
'ComparisonOperator' => 'EQ'
),
'microtime' => array(
'AttributeValueList' => array(
array('N' => strtotime("-1 minutes")*10000)
),
'ComparisonOperator' => 'GT'
)
)
));
foreach ($iterator as $item) {
echo $item['messageId']['S']." ";
}
But how can I modify my request to allow querying by ANY value within the data-field? For example, filter by only those who have [data][other][nested]=1
I've spent the past hours on this issue and I can't get it to work... I am very grateful for any tips, thanks in advance!
I know this was posted in 2014, but I was looking exactly for this answer and so I'd like to share the result in my search to anyone that will land on this question in the future.
Best practice is to store a JSON as a string, but use a Marshaler object to turn the JSON into something that DynamoDB can digest, and that you will be able to query too:
Using marshalJSON method you turn a JSON, as you can see described in this amazon link
For the ones that are looking for a quick example, I add here below the key parts of the procedure:
If you have a JSON like the following
{
"id": "5432c69300594",
"name": {
"first": "Jeremy",
"middle": "C",
"last": "Lindblom"
},
"age": 30,
"phone_numbers": [
{
"type": "mobile",
"number": "5555555555",
"preferred": true
},
{
"type": "home",
"number": "5555555556",
"preferred": false
}
]
}
stored in a string variable $json, you can simply do
use AwsDynamoDbDynamoDbClient;
use AwsDynamoDbMarshaler;
$client = DynamoDbClient::factory(/* your config */);
$marshaler = new Marshaler();
$client->putItem([
'TableName' => 'YourTable',
'Item' => $marshaler->marshalJson($json)
]);
I don't think AWS PHP SDK for DynamoDB has yet implemented the support for JSON based document storage. Their recent notification published on their blog on 8th October 2014, mentions about the support of this new feature only in Java, .NET, Ruby and JS SDK.

Categories