Google Sheets API - 0 cells updated - php

I have a sheet that needs to be updated with some data.
Code that should add «hello» and «bye» to my sheet:
require __DIR__ . '/vendor/autoload.php';
function getClient()
{
...
}
$client = getClient();
$service = new Google_Service_Sheets($client);
$spreadsheetId = 'ID';
$range = 'A1';
$value = [
["hello", "bye"]
];
$body = new Google_Service_Sheets_ValueRange(
["majorDimension" => "ROWS"],
["values" => $value]
);
$params = array('valueInputOption' => 'USER_ENTERED');
$requestBody = new Google_Service_Sheets_ValueRange();
$result = $service->spreadsheets_values->update($spreadsheetId, $range,
$body, $params);
printf("%d cells updated.", $result->getUpdatedCells());
result:
0 cells updated.
I also tried to change $range = 'A1’; to something like Sheet1!A1 or A1-B2 and variety of another ranges; but in that case I receive error:
{ "error":
{ "code": 400, "message": "Unable to parse range: A1-B2",
"errors":
[
{ "message": "Unable to parse range: A1-B2",
"domain": "global",
"reason": "badRequest" } ],
"status": "INVALID_ARGUMENT" } }

How about this modification?
Answer 1:
0 cells updated.
About the reason of above issue, if you want to use "majorDimension" => "ROWS", please modify as follows.
From:
$body = new Google_Service_Sheets_ValueRange(
["majorDimension" => "ROWS"],
["values" => $value]
);
To:
$body = new Google_Service_Sheets_ValueRange([
"majorDimension" => "ROWS",
"values" => $value
]);
In your case, I think that the following modification can be also used.
$body = new Google_Service_Sheets_ValueRange([
"values" => $value
]);
Answer 2:
also tried to change $range = 'A1’; to something like Sheet1!A1 or A1-B2 and variety of another ranges; but in that case I receive error:
About the reason of above issue, if you want to use the range, how about the following modification?
From:
$range = 'A1';
To:
$range = 'Sheet1!A1';
and
$range = 'Sheet1!A1:B1';
References:
Method: spreadsheets.values.update
A1 notation

Related

PHP BigQuery Client Error Code: 401 running long job

I got a PHP BigQueryClient that I use to export big tables to csv from BQ, but after running for a while they throw and error with code 401:
Google\Cloud\Core\Exception\ServiceException
{
"error": {
"code": 401,
"message": "Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
"errors": [
{
"message": "Invalid Credentials",
"domain": "global",
"reason": "authError",
"location": "Authorization",
"locationType": "header"
}
],
"status": "UNAUTHENTICATED"
}
}
it occurs when running a long while that goes over the rows of the table like this
$bigQuery = new BigQueryClient([
'keyFile' => $array[$key],
'projectId' => $this->projectId
]);
//This is to get total row count so we can loop over it
$info = $bigQuery->dataset($this->datasetId)->table($tableName)->info();
//Output row count, and status message
$this->info($this->messagePrepend . "Rows: " . number_format($info['numRows']) . ", Chunk size: " . number_format($this->chunkSize) . " – Processing.." . PHP_EOL);
$startTime = Carbon::now();
//Open our output file
$file = fopen(storage_path("tmp/{$tableName}.csv"), 'w');
fputcsv($file, $this->tableHeaders);
$orderBy = match ($keyword) {
default => "id"
};
while ($info['numRows'] > $offset) {
$config = $bigQuery->query("SELECT * FROM {$this->datasetId}.{$tableName} ORDER BY {$orderBy} ASC LIMIT {$this->chunkSize} OFFSET {$offset}");
$job = $bigQuery->startQuery($config);
$queryResults = collect($job->queryResults());
$queryResults->map(function ($row) {
$line = [FORM LINE]
fputcsv($file, $line);
});
$offset += $this->chunkSize;
}
I've tried looking for the causes for this, and it seems like the issue is that the client token expires after an hour.
Despite that I've not found a way to refresh it, cause it doesn't seem to do so automatically, could anyone help me figure out how to do that?
I've read cloud bigquery docs but they didn't provide me with much answers, and neither did google
Resolved it by updating the instance of BigQueryClient when an exception is thrown:
try {
$job = $bigQuery->startQuery($config);
} catch (\Throwable $th) {
$this->warn("Code: " . $th->getCode() . ": " . $th->getMessage(), 'vvv');
$bigQuery = new BigQueryClient([
'keyFile' => $array[$key],
'projectId' => $this->projectId
]);
$job = $bigQuery->startQuery($config);
}

542{ "error": { "code": 400, "message": "'valueInputOption' is required but not specified", "errors": [ { "mes

I found the same problem with the solution for the same error in javascript but couldn't make it work for PHP so please help
ERROR: 542{ "error": { "code": 400, "message": "'valueInputOption' is required but not specified", "errors": [ { "message": "'valueInputOption' is required but not specified", "domain": "global", "reason": "badRequest" } ], "status": "INVALID_ARGUMENT" } }
this is the error i get when i use the following code:
<?php
$time = time();
$name = $_GET['cname'];
$invoiceNumber = $_GET['invoice'];
$date = $_GET['date'];
$percentage = $_GET['percentage'];
$taxableValue = $_GET['taxableValue'];
$discount = $_GET['discount'];
$invoictotoal = $_GET['total'];
$sgst = $percentage*$taxableValue/100;
echo $discount;
require __DIR__ . '/vendor/autoload.php';
/**
* Returns an authorized API client.
* #return Client the authorized client object
*/
function getClient()
{
$client = new \Google_Client();
$client->setApplicationName('Google Sheets API PHP Quickstart');
$client->setScopes([\Google_Service_Sheets::SPREADSHEETS]);
$client->setAuthConfig('C:\Users\mitta\Desktop\Seagull\form\credentials.json');
$client->setAccessType('offline');
return $client;
}
// Get the API client and construct the service object.
$client = getClient();
$client->addScope(Google\Service\Drive::DRIVE);
$client->setScopes(['https://www.googleapis.com/auth/spreadsheets']);
$service = new Google\Service\Sheets($client);
// Prints the names and majors of students in a sample spreadsheet:
// https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms/edit
try{
$spreadsheetId = '1H6EHEHGsHyRZTE-j8er9DrZjj-b9TkRg0p96K-h90Pc';
$range = 'Form Responses 1';
$valuetoinsert = [
[$time,$name,$invoiceNumber,$date,$percentage,$invoictotoal,$taxableValue,$discount,$sgst,$sgst],
];
$body = new Google_Service_Sheets_ValueRange([
'values' => $valuetoinsert
]);
$params = [
'valueInputOption' => 'RAW'
];
$inset = [
"insertDataOption" => "INSERT_ROWS"
];
$result = $service->spreadsheets_values->append(
$spreadsheetId,
$range,
$body
);
}
catch(Exception $e) {
// TODO(developer) - handle error appropriately
echo $e->getMessage();
}
?>
so i added the valuInputOption parameter but then i get different error
error: Uncaught TypeError: implode(): Argument #2 ($array) must be of type ?array, string given in D:\xamp\htdocs\form\vendor\google\apiclient\src\Google\Service\Resource.php:291 Stack trace: #0 D:\xamp\htdocs\form\vendor\google\apiclient\src\Google\Service\Resource.php(291): implode(Array, '&') #1 D:\xamp\htdocs\form\vendor\google\apiclient\src\Google\Service\Resource.php(190): Google_Service_Resource->createRequestUri('v4/spreadsheets...', Array) #2 D:\xamp\htdocs\form\vendor\google\apiclient-services\src\Sheets\Resource\SpreadsheetsValues.php(83): Google_Service_Resource->call('append', Array, 'Google\Service\...') #3 D:\xamp\htdocs\form\insert.php(54): Google\Service\Sheets\Resource\SpreadsheetsValues->append('1H6EHEHGsHyRZTE...', 'Form Responses ...', Object(Google\Service\Sheets\ValueRange), Array, Array) #4 {main} thrown in D:\xamp\htdocs\form\vendor\google\apiclient\src\Google\Service\Resource.php on line 291
The code used for this error is the sam and i added 2 more parameters:
$result = $service->spreadsheets_values->append(
$spreadsheetId,
$range,
$body,
$inset,
$params
);

How to insert text with google docs api php

I'm trying to create a copy of a document using the Google Docs Api, and then edit it that copy by inserting text into it. So, I've looked at the documentation and seemingly implemented it exactly the way it says.
<?php
//That is, if this is just a regular login
//Personal Files
require("loginManager.php");
require("globals.php");
require("googleDrive.php");
//Moodle files
require("../config.php");
require("../my/lib.php");
require("../files/renderer.php");
require("../course/lib.php");
//Google Docs
$CREDENTIALS_PATH = "../../" . "vendor/autoload.php";
require ($CREDENTIALS_PATH);
//Example code
$copyTitle = 'Copy Title';
$documentId = "1vYyeGLbadFi0sl9g2LEJSZCB4YiGOpCb";
$copy = new Google_Service_Drive_DriveFile(array(
'name' => $copyTitle
));
//Initialize necessary client variables
$desiredPath = "../../credentials.json";
$authCode = (isset($_GET["code"]) ? $_GET["code"]:"");
GoogleDrive::setAuthCode($authCode);
$client = GoogleDrive::getClient($desiredPath, $FULLSCRIPT);
$docServices = new Google_Service_Docs($client);
$driveServices = new Google_Service_Drive($client);
$files = $driveServices->files;
$documents = $docServices->documents;
$driveResponse = $files->copy($documentId, $copy);
$documentCopyId = $driveResponse->id;
//Create desiredRequests
$desiredRequests = array(new Google_Service_Docs_Request(array(
'insertText' => array(
'text' => 'Hello world!',
'location' => array(
'index' => 25)))));
$batchUpdateRequests = new Google_Service_Docs_BatchUpdateDocumentRequest(array(
'requests' => $desiredRequests));
$docChangeResponse = $documents->batchUpdate($documentCopyId, $batchUpdateRequests);
echo $OUTPUT->header();
echo $OUTPUT->custom_block_region('content');
echo $OUTPUT->footer();
//Check if there's any get actions that need to be serviced
$getVariable = filter_input(INPUT_GET, "action");
if($getVariable == "openFileManager") {core_files_renderer::render_form_filemanager();}
else if($getVariable == "createCourse")
{
/*Important note: there are two types of ids when it comes to courses
*
* Programmer's Notes:
*
* -$instance is the instance of a record of from the enrol table
* -the enrol table stores instances of courses...so does mdl_course
* -idnumber and id, the latter is the actual primary key, the other is
* I guess is for school admins or course creators to be able to number
* the courses according to their own system. idnumber can be null.
*
*/
$enrollmentPlugin = enrol_get_plugin("manual");
if($enrollmentPlugin)
{
//Create data for course_request
$data = new stdClass();
$data->requester = $USER->id;
$data->id = 1;
$course_request_object = new course_request($data);
unset($data);
//create data for new course
$data = new stdClass();
$data->fullname = 'Math';
$data->shortname = 'Math 7';
$data->summary = 'Awesome!';
$data->summaryformat = FORMAT_PLAIN;
$data->format = 'topics';
$data->newsitems = 0;
$data->numsections = 5;
//$data->category = $course_request_object->get_category();
$data->category = 1;
$course = create_course($data);
//Instance is the record from the enrol table
$instanceid = $enrollmentPlugin->add_instance($course);
$instance = $DB->get_record('enrol', array('courseid'=>$course->id, 'enrol'=>'manual'), '*', MUST_EXIST);
$enrollmentPlugin->enrol_user($instance, $USER->id);
}
}
else if($getVariable == "appendDocument")
{
$courseID = filter_input(INPUT_GET, "courseID");
$fs = get_file_storage();
$data = array(
'contextid' => $courseID, // ID of context
'component' => 'course_myarea', // usually = table name
'filearea' => 'myarea', // usually = table name
'itemid' => 0, // usually = ID of row in table
'filepath' => '/', // any path beginning and ending in /
'filename' => 'myfile.txt'
);
$content = "hellp worldl";
$fs->create_file_from_string($data, $content);
}
else if($getvariable == null)
{
//if there are no get paramaters then it's a first time entry
//get all of user's courses, files, etc
$courses = enrol_get_all_users_courses($USER->id);
global $DB;
foreach($courses as $currentCourse)
{
$desiredID = $currentCourse->id;
$desiredFiles = $DB->get_record('files', array('contextid'=> $desiredID));
$contentHash = $desiredFiles->contenthash;
$dir1 = substr($contentHash, 0, 2); $dir2 = substr($contentHash, 2, 2);
$desiredPath = $CFG->dirrot."../../../../moodledata/filedir/"
.$dir1."/".$dir2."/".$contentHash;
$myFile = file_get_contents($desiredPath);
$type = mime_content_type($desiredPath);
$contentTypes = array("pdf" => "application/pdf",
"txt" => "text/plain");
//header("Content-Type: application/pdf");
//readfile($desiredPath, false, $foo);
$myFile = file_get_contents("goedel.pdf");
$foo = 3;
}
}
?>
Here's where GoogleDrive::getClient is defined in case it helps
class GoogleDrive
{
private static $AUTH_CODE;
public static function setAuthCode($desiredCode)
{
self::$AUTH_CODE = $desiredCode;
}
public static function getClient($credentialsPath, $callbackScript)
{
$client = new Google_Client();
$client->setApplicationName('MyApp');
$client->setScopes(Google_Service_Drive::DRIVE);
$client->setAuthConfig($credentialsPath);
$client->setAccessType('online');
$client->setPrompt('select_account consent');
$desiredVariable = self::$AUTH_CODE;
if($desiredVariable != null)
{
$accessToken = $client->fetchAccessTokenWithAuthCode($desiredVariable);
$client->setAccessToken($accessToken);
return $client;
}
// Load previously authorized token from a file, if it exists.
// The file token.json stores the user's access and refresh tokens, and is
// created automatically when the authorization flow completes for the first
// time.
$tokenPath = 'token.json';
if (file_exists($tokenPath)) {
$accessToken = json_decode(file_get_contents($tokenPath), true);
$client->setAccessToken($accessToken);
}
// If there is no previous token or it's expired.
if ($client->isAccessTokenExpired()) {
// Refresh the token if possible, else fetch a new one.
if ($client->getRefreshToken()) {
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
} else {
// Request authorization from the user.
$authUrl = $client->createAuthUrl();
$client->setRedirectUri($callbackScript);
redirect($authUrl);
// Exchange authorization code for an access token.
$accessToken = $client->fetchAccessTokenWithAuthCode($authCode);
$client->setAccessToken($accessToken);
// Check to see if there was an error.
if (array_key_exists('error', $accessToken)) {
throw new Exception(join(', ', $accessToken));
}
}
// Save the token to a file.
if (!file_exists(dirname($tokenPath))) {
mkdir(dirname($tokenPath), 0700, true);
}
file_put_contents($tokenPath, json_encode($client->getAccessToken()));
}
return $client;
}
}
However, when I run the previous code I get this error.
"{
"error": {
"code": 400,
"message": "This operation is not supported for this document",
"errors": [
{
"message": "This operation is not supported for this document",
"domain": "global",
"reason": "failedPrecondition"
}
],
"status": "FAILED_PRECONDITION"
}
}
"
Any help or direction will be greatly appreciated.
Edit 1: I've changed the script to reflect Tanaike's solution
I believe your situation and goal as follows.
You have already been able to use Google Docs API.
The script of a copy of a document worked.
You want to remove the error in your question.
For this, how about this modification?
From:
$desiredRequests = new Google_Service_Docs_Request(array(
'insertText' => array(
'text' => 'Hello world!',
'location' => array(
'index' => 25))));
In your script, when $batchUpdateRequests is retrieved, it becomes as follows.
{"requests":{"createNamedRangeType":{},"createNamedRangeDataType":{},"createParagraphBulletsType":{},"createParagraphBulletsDataType":{},"deleteContentRangeType":{},"deleteContentRangeDataType":{},"deleteNamedRangeType":{},"deleteNamedRangeDataType":{},"deleteParagraphBulletsType":{},"deleteParagraphBulletsDataType":{},"deletePositionedObjectType":{},"deletePositionedObjectDataType":{},"deleteTableColumnType":{},"deleteTableColumnDataType":{},"deleteTableRowType":{},"deleteTableRowDataType":{},"insertInlineImageType":{},"insertInlineImageDataType":{},"insertTableRowType":{},"insertTableRowDataType":{},"insertTextType":{},"insertTextDataType":{},"replaceAllTextType":{},"replaceAllTextDataType":{},"updateParagraphStyleType":{},"updateParagraphStyleDataType":{},"updateTextStyleType":{},"updateTextStyleDataType":{},"internal_gapi_mappings":{},"modelData":{},"processed":{},"insertText":{}}}
I think that this is the reason of your issue.
To:
$desiredRequests = array(new Google_Service_Docs_Request(array(
'insertText' => array(
'text' => 'Hello world!',
'location' => array(
'index' => 25)))));
In this modified script, when $batchUpdateRequests is retrieved, it becomes as follows.
{"requests":[{"insertText":{"text":"Hello world!","location":{"index":25,"segmentId":null}}}]}
In this request body, I could confirm that it worked.
Note:
If an error like Invalid requests[0].insertText: Index 25 must be less than the end index of the referenced segment occurs, please modify 'index' => 25 to 'index' => 1.
Reference:
Method: documents.batchUpdate

Linkedin Api Visibillity

I spent some time without touching this Api, and now I have received the following error:
Unpermitted fields present in REQUEST_BODY:
It's a sharing code:
$link = 'https://example.com.br';
$access_token = $access_token;
$linkedin_id = $linkedin_profile_id;
$body = new \stdClass();
$body->content = new \stdClass();
$body->content->contentEntities[0] = new \stdClass();
$body->text = new \stdClass();
$body->content->contentEntities[0]->thumbnails[0] = new \stdClass();
$body->content->contentEntities[0]->entityLocation = $link;
$body->content->contentEntities[0]->thumbnails[0]->resolvedUrl = "https://example.com.br/img/logo-header-120x50.png";
$body->content->title = 'Example';
$body->owner = 'urn:li:person:'.$linkedin_id;
$body->text->text = 'Kasum';
$body->visibility = new \stdClass();
$body->visibility->code = new \stdClass();
$body->visibility->code = 'anyone';//<-------------that is a line error
$body_json = json_encode($body, true);
try {
$client = new Client(['base_uri' => 'https://api.linkedin.com']);
$response = $client->request('POST', '/v2/shares', [
'headers' => [
"Authorization" => "Bearer " . $access_token,
"Content-Type" => "application/json",
"x-li-format" => "json"
],
'body' => $body_json,
]);
if ($response->getStatusCode() !== 201) {
echo 'Error: '. $response->getLastBody()->errors[0]->message;
}
echo 'Post is shared on LinkedIn successfully';
} catch(Exception $e) {
echo $e->getMessage(). ' for link '. $link;
}
As indicated in the code, the visibility field triggers this error
Without it, sharing occurs, but with visibility only for connections. That way the post loses the share button.
Is it no longer allowed to configure this field, or am I doing it wrong?

Ebay Api, getOrders. Can't get buyer email

Everybody.
Have a question about ebay trading api.
I'm trying to get all orders for authorized user.
I'm developing my web application using PHP.
So, I use this sdk:
https://github.com/davidtsadler/ebay-sdk-php
I'm getting list using getOrders method:
http://developer.ebay.com/devzone/xml/docs/Reference/ebay/GetOrders.html
Here is my code example:
public function getOrders(){
$service = $this->getTradingService();
$args = array(
//"OrderStatus" => "Completed",
"OrderStatus" => "All",
"SortingOrder" => "Ascending",
"OrderRole" => "Seller",
//"CreateTimeFrom" => new \DateTime('2015-01-01'),
"CreateTimeFrom" => new \DateTime('2000-01-01'),
"CreateTimeTo" => new \DateTime(),
);
$request = new Types\GetOrdersRequestType($args);
$request->RequesterCredentials = new Types\CustomSecurityHeaderType();
$request->RequesterCredentials->eBayAuthToken = $this->userToken;
$request->IncludeFinalValueFee = true;
$request->Pagination = new Types\PaginationType();
$request->Pagination->EntriesPerPage = 100;
$pageNum = 1;
$orders = [];
do {
$request->Pagination->PageNumber = $pageNum;
$response = $service->getOrders($request);
if (isset($response->Errors)) {
$message = '';
foreach ($response->Errors as $error) {
$message .= $error->ShortMessage;
}
throw new Exception($message);
}
if ($response->Ack !== 'Failure' && isset($response->OrderArray)) {
foreach ($response->OrderArray->Order as $order) {
$orders[] = $order->toArray();
}
}
$pageNum += 1;
}
while(isset($response->OrderArray) && $pageNum <= $response->PaginationResult->TotalNumberOfPages);
return $orders;
}
It works fine for me except one issue.
I can't get buyer email.
$orders[0]['ShippingAddress']['ExternalAddressID']
Is empty.
$orders[0]['TransactionArray']['Transaction'][0]['Buyer']['Email']
Is string value "Invalid Request"
If somebody knows way to get buyers emails.
Or just get informatioan about many users in one request(so I could simply merge them).
UPDATE:
Also tried to do the same without SDK.
public function getOrders2(){
$xml = '<?xml version="1.0" encoding="utf-8"?>
<GetOrdersRequest xmlns="urn:ebay:apis:eBLBaseComponents">
<CreateTimeFrom>2000-01-01T00:00:00</CreateTimeFrom>
<CreateTimeTo>2015-10-22T00:00:00</CreateTimeTo>
<IncludeFinalValueFee>true</IncludeFinalValueFee>
<OrderRole>Seller</OrderRole>
<OrderStatus>All</OrderStatus>
<DetailLevel>ReturnAll</DetailLevel>
<RequesterCredentials>
<eBayAuthToken>' . $this->userToken . '</eBayAuthToken>
</RequesterCredentials>
</GetOrdersRequest>';
$url = 'https://api.ebay.com/ws/api.dll';
$results = $this->sendPostRequest($xml,$url);
$results = new SimpleXMLElement($results);
return $results;
}
Get the same issue.
Thanks
Need change SiteID to id User Registration.
$config = [
'apiVersion' => Services\TradingService::API_VERSION,
'siteId' => Constants\SiteIds::US,
'credentials' => [
'appId' => getenv('EBAY_APP_ID'),
'certId' => getenv('EBAY_CERT_ID'),
'devId' => getenv('EBAY_DEV_ID')
],
'sandbox' => false
];
If the order is too old then it will will result in Invalid Request ( Simply saying " This orders is XX days old and we wont provide email address for it )
Ebay withholds their user's email information 14 days after the order is placed.
If you are using their APIs to pulling order info after that you get:
Email = 'Invalild Request'
Example response ...
...
'TransactionArray': {'Transaction': [...
'Buyer': {'Email': 'Invalid Request',
'UserFirstName': None,
'UserLastName': None},
...
The thing to do is
Pull the data before that, and then
Do not update the order email data on subsequent data pulls.
I found this out the hard way. I don't recall reading about that in the API docs.

Categories