Update DeveloperMetadata of google sheet using google sheet api - php

I am using Google APIs Client Library for PHP. I can create and access the DeveloperMetadata of the spreadsheet. But cannot update the DeveloperMetadata. Please see the below code for a better understanding.
<?php
class GoogleSheetHelper {
function update_dev_meta() {
$dev_meta = new DeveloperMetadata();
$dev_meta->setVisibility( 'DOCUMENT' );
$dev_meta->setMetadataKey( 'new_meta_key' );
$dev_meta->setMetadataValue( 'new_meta_value_updated' );
$update_req = new UpdateDeveloperMetadataRequest();
$update_req->setDeveloperMetadata( $dev_meta );
$update_req->setFields( '*' );
$request = new Request();
$request->setUpdateDeveloperMetadata( $update_req );
$batch_update = new BatchUpdateSpreadsheetRequest();
$batch_update->setRequests( [ $request ] );
$client = $this->get_client();
$service = new Sheets( $client );
try {
return $service->spreadsheets->batchUpdate( $spreadsheet_id, $batch_update );
} catch ( Exception $ex ) {
var_dump( $ex->getErrors() );
return false;
}
}
private function get_client( $scopes = [] ) {
$credential = 'location/of/credential.json';
if ( empty( $credential ) ) {
return null;
}
$default_scopes = [
'https://www.googleapis.com/auth/drive',
'https://www.googleapis.com/auth/spreadsheets',
];
return new Client(
[
'credentials' => $credential,
'scopes' => $default_scopes,
]
);
}
}
Feel free to notify me of any queries. Sorry for my poor English skill.

Checking your code and the documentation it seems that you are missing to specify a Data Filter and a DeveloperMetadata Object including a field mask that declares fields to be updated. Please check the documentation on how to update the developer metadata to corroborate you are doing it properly.
Here is the example shown that updates the developer metadata, it's not that far from what you currently have:
{
"requests": [
{
"updateDeveloperMetadata": {
"dataFilters": [
{
"developerMetadataLookup": {
"metadataId": metadataId
}
}
],
"developerMetadata": {
"location": {
"sheetId": sheetId
},
"metadataKey": "SalesUpdated"
},
"fields": "location,metadataKey"
}
}
]
}

Related

Set Sheet Data before creating google Spreadsheet

I am using Google APIs Client Library for PHP to create a spreadsheet. I am creating a spreadsheet with 3 sheets in it. Now I need to insert a row on each sheet before attaching them to the spreadsheet. Is there a way to populate the sheets with some data? All I want is to create the sheet in one request with all the data I need. Please see the below code for a better understanding:
<?php
class GoogleSheetFunctions {
public function create_new() {
$client = $this->get_client();
if ( is_null( $client ) ) {
return false;
}
$service = new Sheets( $client );
$spreadsheet = $this->set_spreadsheet_title();
$spreadsheet = $this->set_spreadsheet_with_sheets( $spreadsheet );
// making the request to create a new spreadsheet in google
try {
$response = $service->spreadsheets->create( $spreadsheet );
$spreadsheet_id = $response->spreadsheetId;
} catch ( Exception $ex ) {
return false;
}
if ( ! $permission ) {
return false;
}
return true;
}
protected function set_spreadsheet_with_sheets( Spreadsheet $spreadsheet ) {
$sheet_names = [
'sheet-no-1',
'sheet-no-2',
'sheet-no-3',
];
$sheets = [];
// creating sheets as per sheet names
foreach ( $sheet_names as $sheet ) {
$sheet_properties = new SheetProperties();
$sheet_properties->setTitle( $sheet );
$temp_sheet = new Sheet();
$temp_sheet->setProperties( $sheet_properties );
// generate a first row with custom data for each sheet
$sheets[] = $temp_sheet;
}
// set the created sheets to the main spreadsheet
$spreadsheet->setSheets( $sheets );
return $spreadsheet;
}
protected function set_spreadsheet_title() {
$month = current_datetime()->format( 'F-Y' );
$spreadsheet_name = $month;
$spreadsheet_props = new SpreadsheetProperties();
$spreadsheet_props->setTitle( $spreadsheet_name );
$spreadsheet = new Spreadsheet();
$spreadsheet->setProperties( $spreadsheet_props );
return $spreadsheet;
}
protected function get_client( $scopes = [] ) {
$credential = 'location/of/credential.json';
$scopes = [
'https://www.googleapis.com/auth/drive',
'https://www.googleapis.com/auth/spreadsheets',
];
return new Client( [
'credentials' => $credential,
'scopes' => $scopes,
] );
}
}
Feel free to notify me of any queries. Sorry for my poor English skill.

Symfony 4 FindBy() and returning an array via JSON

I have the following line of code
$apps = $appRepositry->findBy(['user' => $user]);
I then return the results via JSON using the following
$json_data[] = array(
"state" => "success",
"user_apps" => $apps,
"total_registerd_apps" => count($apps),
);
The issue I have is that the count is correct but the "user_apps" array is returning blank.
{
state = success;
"total_registerd_apps" = 1;
"user_apps" = (
{
}
);
}
I think it is because the FindBy returns objects but I am not sure. Could someone explain how to convert the result to an array that can then be sent via JSON?
Thanks
You need to use a serializer with groups.
Information about serialization :
http://symfony.com/doc/current/components/serializer.html
Information about serialization groups :
https://symfony.com/blog/new-in-symfony-2-7-serialization-groups
public function listAction(ParamFetcherInterface $paramFetcher, Request $request)
{
//...your code...//
$yourObjectifiedResult = $appRepositry->findBy(['user' => $user]);
$yourNormalizedResult = $this->normalizeWithCircularHandler(
$yourObjectifiedResult,
['groups']);
//Serializer will convert your result from Object to Json Array automatically. To get a specific set of data, you can use groups.
}
public function normalizeWithCircularHandler($data, $displayGroups, $normalizerCallbacks = false)
{
$encoder = new JsonEncoder();
$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
$normalizer = new ObjectNormalizer($classMetadataFactory);
$normalizer->setCircularReferenceHandler(function ($object) {
return $object->getId();
});
if(false != $normalizerCallbacks && is_array($normalizerCallbacks)) {
$normalizer->setCallbacks($normalizerCallbacks);
}
$serializer = new Serializer([$normalizer], [$encoder]);
return $serializer->normalize($data , null, ['groups' => $displayGroups]);
}
You need to use a serializer to serialize your data into JSON:
https://symfony.com/doc/current/serializer.html

Async HTML parser with Goutte

I am trying to write HTML parser with the help of Goutte. It works very well. However Goutte uses blocking requests. This works well if you are dealing with a single service. If I want to query lots of services which are independent from each other, this causes a problem. Goutte uses BrowserKit and Guzzle. I have tried to change doRequest function but it failed with
Argument 1 passed to
Symfony\Component\BrowserKit\CookieJar::updateFromResponse() must be
an instance of Symfony\Component\BrowserKit\Response
protected function doRequest($request)
{
$headers = array();
foreach ($request->getServer() as $key => $val) {
$key = strtolower(str_replace('_', '-', $key));
$contentHeaders = array('content-length' => true, 'content-md5' => true, 'content-type' => true);
if (0 === strpos($key, 'http-')) {
$headers[substr($key, 5)] = $val;
}
// CONTENT_* are not prefixed with HTTP_
elseif (isset($contentHeaders[$key])) {
$headers[$key] = $val;
}
}
$cookies = CookieJar::fromArray(
$this->getCookieJar()->allRawValues($request->getUri()),
parse_url($request->getUri(), PHP_URL_HOST)
);
$requestOptions = array(
'cookies' => $cookies,
'allow_redirects' => false,
'auth' => $this->auth,
);
if (!in_array($request->getMethod(), array('GET', 'HEAD'))) {
if (null !== $content = $request->getContent()) {
$requestOptions['body'] = $content;
} else {
if ($files = $request->getFiles()) {
$requestOptions['multipart'] = [];
$this->addPostFields($request->getParameters(), $requestOptions['multipart']);
$this->addPostFiles($files, $requestOptions['multipart']);
} else {
$requestOptions['form_params'] = $request->getParameters();
}
}
}
if (!empty($headers)) {
$requestOptions['headers'] = $headers;
}
$method = $request->getMethod();
$uri = $request->getUri();
foreach ($this->headers as $name => $value) {
$requestOptions['headers'][$name] = $value;
}
// Let BrowserKit handle redirects
$promise = $this->getClient()->requestAsync($method,$uri,$requestOptions);
$promise->then(
function (ResponseInterface $response) {
return $this->createResponse($response);
},
function (RequestException $e) {
$response = $e->getResponse();
if (null === $response) {
throw $e;
}
}
);
$promise->wait();
}
How can I change Goutte\Client.php so that it does requests asynchronously? Is that is not possible, how can I run my scrappers which targets different endpoints simultaneously? Thanks
Goutte is essentially a bridge between Guzzle and Symphony's Browserkit and DomCrawler.
The biggest drawback with using Goutte is that all requests are made sychronouslly
To complete things asychronously you will have to forego using Goutte and directly use Guzzle and DomCrawler.
For example:
$requests = [
new GuzzleHttp\Psr7\Request('GET', $uri[0]),
new GuzzleHttp\Psr7\Request('GET', $uri[1]),
new GuzzleHttp\Psr7\Request('GET', $uri[2]),
new GuzzleHttp\Psr7\Request('GET', $uri[3]),
new GuzzleHttp\Psr7\Request('GET', $uri[4]),
new GuzzleHttp\Psr7\Request('GET', $uri[5]),
new GuzzleHttp\Psr7\Request('GET', $uri[6]),
];
$client = new GuzzleHttp\Client();
$pool = new GuzzleHttp\Pool($client, $requests, [
'concurreny' => 5, //how many concurrent requests we want active at any given time
'fulfilled' => function ($response, $index) {
$crawler = new Symfony\Component\DomCrawler\Crawler(null, $uri[$index]);
$crawler->addContent(
$response->getBody()->__toString(),
$response->getHeader['Content-Type'][0]
);
},
'rejected' => function ($response, $index) {
// do something if the request failed.
},
]);
$promise = $pool->promise();
$promise->wait();

ZF2 rest api coding style (camel-case or underscore)

I am writing the code with the following for mat in rest api.
I thought that, validation done in controller and the service layer cares of writing business logic and model takes care of database operations. I hope I am correct.
My clarification here is whether I can send var_id (underscore separated) to the service layer or as varID (camel-case).
I searched that lot of the api calls, most of them are var_id, that's the reason I used myself too.
But how can I use the variable here, because zend framework code works with camel-case, if am assigning the variables varID = var_id for each and every variable, is it right.
$dataSendToService = array(
$varID = var_id,
$varID2 = var_id2;
);
I am calling the api like the below in the create method.
http://128.12.788.88/api/v1/users/72
json get method like this
{
"var_id":"var_value",
"var_id1":"var_value1"
}
In controller:
function create() {
$body = $this->getRequest()->getContent();
$data = json_decode($body);
$id = $this->params('id');
//validation
if( !isset( $data->pat_id ) || empty( $data->pat_id ) ) {
$resp = array(
'status' => 'failure',
'errorCode' => 531,
'errorMessage' => 'Patient ID should not be empty'
);
return new JsonModel($resp);
}
if( !isset( $data->doc_id ) || empty($data->doc_id )) {
$resp = array(
'status' => 'failure',
'errorCode' => 532,
'errorMessage' => 'Doctor ID should not be empty'
);
return new JsonModel($resp);
}
if( !isset( $data->apt_time ) || empty($data->apt_time )) {
$resp = array(
'status' => 'failure',
'errorCode' => 533,
'errorMessage' => 'Appointment time should not be empty');
return new JsonModel($resp);
}
if( !isset( $data->apt_subject ) || empty($data->apt_subject )) {
$resp = array(
'status' => 'failure',
'errorCode' => 534,
'errorMessage' => 'Appointment Subject time should not be empty');
return new JsonModel($resp);
}
$sm = $this->getServiceLocator();
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$usersService = new UsersService($dbAdapter);
$resp = $usersService->profile($data,$id);
}
In service:
function create() {
//get the data and pass it to model
}
In model:
function create() {
//get the data and insert in table and return the result
}
It is totally fine to use underscore separated values in ZF2 but indeed camel-casing seems to be more common practice.
You definitely don't have to do all this manually, you can easily use filters for changing your json variables to camel-case:
use Zend\Filter\Word\CamelCaseToUnderscore;
...
$filter = new CamelCaseToUnderscore();
print $filter->filter('ThisIsMyContent');
And back to underscore separated:
use Zend\Filter\Word\CamelCaseToDash;
...
filter = new CamelCaseToDash();
print $filter->filter('ThisIsMyContent');
If you use a hydrator then you can use the ZF2 ClassMethods hydrator which can be set to extract and hydrate between both by passing a boolean to the constructor:
underscore-separated (true) or camel-case (false)
use Zend\Stdlib\Hydrator\ClassMethods;
...
$boolean = true|false;
$hydrator = new ClassMethods($boolean)

oneupuploader with jQuery-File-Upload UI

I'm trying to setup jQuery-File-Upload UI with oneupuploaderBundle on a symfony2 Website.
After a lot of tears, the upload process works as I want,but I can't make the Json response work avec the upload.
I use the PostUploadEvent of the oneupuploaderBundle, And tied a lot of solution to send a corecte jSon response to jQuery-File-Upload UI, but i still have an error message when the file has been uploaded.
In the doc, the ask to send a resonse like this:
{"files": [
{
"name": "picture1.jpg",
"size": 902604,
"url": "http:\/\/example.org\/files\/picture1.jpg",
"thumbnail_url": "http:\/\/example.org\/files\/thumbnail\/picture1.jpg",
"delete_url": "http:\/\/example.org\/files\/picture1.jpg",
"delete_type": "DELETE"
}
]}
Here is mine :
{"files": [
{
"url": "\/ishowpro-cms\/web\/app_dev.php\/library\/file\/image\/originals\/51dbd9a13a065-screen-shot-mini.png",
"thumbnail_url": "\/ishowpro-cms\/web\/app_dev.php\/library\/file\/image\/thumbnails\/51dbd9a13a065-screen-shot-mini.png",
"name": "screen-shot-mini.png",
"type": "image/png",
"size": 1192,
"delete_url": "http://nourltodelete.com",
delete_type: "DELETE"
}
] }
The URls are OK.
I tried to return the response with
return new JsonResponse($jsonResponse);
with the Normal response object and json headers, I tried to create an entity and serialize it :
$responseObjectFile = new JqUploaderFile();
$responseObjectFile->setName();
$responseObjectFile->setSize();
$responseObjectFile->setUrl();
$responseObjectFile->setThumbnail_url();
$responseObjectFile->setDelete_url($this->router->generate('show_image_link', array('slug'=>$file->getSlug(), 'extension'=>$file->getExtension(), 'size'=>'originals'), true));
$responseObjectFile->setDelete_type("DELETE");
//create serializer to encode Entity
$encoders = array(new XmlEncoder(), new JsonEncoder());
$normalizers = array(new GetSetMethodNormalizer());
$serializer = new Serializer($normalizers, $encoders);
$jsonContent = $serializer->serialize($responseObjectFile, 'json');
//add entity in array and unserilize it....
$responseCode = array('files'=>array($jsonContent) );
And also to use the $event->getRequest(); of the object.
But nothing works.
Is their someone who can help me please ?
Thank you in advance.
Here is the complete file
<?php
namespace Reyner\Ishowpro\LibraryBundle\Upload;
use Oneup\UploaderBundle\Event\PostUploadEvent;
use Oneup\UploaderBundle\Event\PreUploadEvent;
use Reyner\Ishowpro\LibraryBundle\Tools\Tools;
use Reyner\Ishowpro\LibraryBundle\Entity\Folder;
use Reyner\Ishowpro\LibraryBundle\Entity\File;
use Reyner\Ishowpro\LibraryBundle\Entity\JqUploaderFile;
use Symfony\Component\HttpFoundation\File\File as sfFile;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Serializer\Encoder\XmlEncoder;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer;
use Gaufrette\File as GaufretteFile;
class UploadListener
{
private $doctrine;
private $logger;
private $router;
public function __construct($doctrine, $logger, \Symfony\Bundle\FrameworkBundle\Routing\Router $router)
{
$this->doctrine = $doctrine;
$this->logger = $logger;
$this->router = $router;
}
public function onPreUpload(PreUploadEvent $event)
{
$file = $event->getFile();
}
public function onUpload(PostUploadEvent $event)
{
$this->logger->info('----------------------------------------------------');
$this->logger->info('------------------ service begin ----------------------');
$request = $event->getRequest();
//$requestFile = $request->files->all();
//$this->logger->info($requestFile["files"][0]->getClientOriginalName());
$em = $this->doctrine->getManager();
$tempfile = $event->getFile();
$parameters = $request->request->all();
/* getFile: Get the uploaded file. Is either an instance of Gaufrette\File or Symfony\Component\HttpFoundation\File\File.
getRequest: Get the current request including custom variables.
getResponse: Get the response object to add custom return data.
getType: Get the name of the mapping of the current upload. Useful if you have multiple mappings and EventListeners.
getConfig: Get the config of the mapping.
*/
$parameters = $request->query->all();
//stock ids to add "new" badges
$newIds = array();
$folder = $em->getRepository('LibraryBundle:Folder')->find($request->getSession()->get('currentFolder'));
$library = $em->getRepository('LibraryBundle:Library')->find($request->getSession()->get('libraryId'));
// $this->logger->info('folder: '.$folder->getId());
//persit in BDD
$file = new File();
$file->setLibrary($library);
$file->setFolder($folder);
$file->setSize($tempfile->getSize());
$filenamePart = explode("--", $tempfile->getName());
$pathinfo = pathinfo($tempfile->getName());
$file->setExtension(strtolower($pathinfo["extension"]));
$file->setName($pathinfo['filename']);
//check mime type and correct it if docx, xlsx or pptx
if(Tools::getMymeTypeFromExt($pathinfo["extension"])){
$file->setMimetype(Tools::getMymeTypeFromExt($pathinfo["extension"]));
}else{
$fi = new \finfo(FILEINFO_MIME_TYPE);
$file->setMimetype($fi->buffer($tempfile->getContent()));
}
$file->setFilename($filenamePart[1]);
$em->persist($file);
$em->flush();
//create thumb
if($file->isImage()){
$this->logger->info('is an Image');
$imagepath = $file->getLocalFileDirectory().$tempfile->getName();
$this->logger->info('image path: '.$imagepath);
$file->encodeAndMoveFile($imagepath);
$this->logger->info('----------------------------------------------------');
}else{
$this->logger->info('is not an Image');
$this->logger->info($file->getLocalFileDirectory().$tempfile->getName());
$file->moveTempFile($file->getLocalFileDirectory().$tempfile->getName());
}
//add id to the New session array
if($request->getSession()->get("newfilesids")){
$newIds = unserialize($request->getSession()->get("newfilesids"));
}
$newIds[] = $file->getId();
$request->getSession()->set("newfilesids", serialize($newIds));
$this->logger->info('JqUploaderFile');
$this->logger->info('----------------------------------------------------');
/********************************************
*
* BUILD RESPONSE
*
******************************************/
$this->logger->info('BUILD RESPONSE');
/*//test1
//create object needed to JqUploader response
$responseObjectFile = new JqUploaderFile();
$responseObjectFile->setName($file->getFileName());
$responseObjectFile->setSize($file->getSize());
$responseObjectFile->setUrl($this->router->generate('show_image_link', array('slug'=>$file->getSlug(), 'extension'=>$file->getExtension(), 'size'=>'originals'), true));
$responseObjectFile->setThumbnail_url($this->router->generate('show_image_link', array('slug'=>$file->getSlug(), 'extension'=>$file->getExtension(), 'size'=>'thumbnails'), true));
$responseObjectFile->setDelete_url($this->router->generate('show_image_link', array('slug'=>$file->getSlug(), 'extension'=>$file->getExtension(), 'size'=>'originals'), true));
$responseObjectFile->setDelete_type("DELETE");
$this->logger->info('-------------------------------------------------------');
$this->logger->info('ENTITY READY');
*/
//test 2
$response = $event->getResponse();
$response["file"][]['name'] = $file->getFileName();
$response["file"][]['size'] = $file->getSize();
$response["file"][]['url'] = $this->router->generate('show_image_link', array('slug'=>$file->getSlug(), 'extension'=>$file->getExtension(), 'size'=>'originals'), true);
$response["file"][]['thumbnail_url'] = $this->router->generate('show_image_link', array('slug'=>$file->getSlug(), 'extension'=>$file->getExtension(), 'size'=>'thumbnails'), true);
$response["file"][]['delete_url'] = $this->router->generate('show_image_link', array('slug'=>$file->getSlug(), 'extension'=>$file->getExtension(), 'size'=>'originals'), true);
$response["file"][]['delete_type'] = "DELETE";
return $response;
//test 3
/*
$jsonResponse = '{"files": [ { "url": '.json_encode($this->router->generate('show_image_link', array('slug'=>$file->getSlug(), 'extension'=>$file->getExtension(), 'size'=>'originals'), true)).', "thumbnail_url": '.json_encode($this->router->generate('show_image_link', array('slug'=>$file->getSlug(), 'extension'=>$file->getExtension(), 'size'=>'thumbnails'), true)).', "name": '.json_encode($file->getFileName()).', "type": "'.$file->getMimeType().'", "size": '.$file->getSize().', "delete_url": "http://nourltodelete.com", "delete_type": "DELETE" } ] }';
return $jsonResponse;
*/
}
}
Thanks to devsheeep, here is the solution.
Really simple when you know it :
$response = $event->getResponse();
$files = array();
$files[0] = array(
'name' => $file->getFileName(),
'size' => $file->getSize(),
'url' => "Your URL",
'thumbnail_url' => "Your thumb URL",
'delete_url' =>"Your delete URL",
'delete_type' => 'DELETE'
);
$response['files'] = $files;
And we are in an Event context, return values have no effects. Instead we are working with references. So just omit the return statement.
5 to create it, I love.
Thanks again to desheep and the 1up.io team, they are great professionals of the Symfony Framework.

Categories