I am using Alexa-php-toolkit for Dynamics 365 https://github.com/AlexaCRM/php-crm-toolkit, using this I can successfully create new contact but I can't add an account name with the contact, when I try I get this error:
Notice: Property accountid of the contact entity cannot be set in ../vendor/alexacrm/php-crm-toolkit/src/Entity.php on line 263.
Here is my script.
<?php
//URL: https://github.com/AlexaCRM/php-crm-toolkit
/**
* Use init.php if you didn't install the package via Composer
*/
use AlexaCRM\CRMToolkit\Client as OrganizationService;
use AlexaCRM\CRMToolkit\Settings;
require_once '../vendor/autoload.php';
require_once '../vendor/alexacrm/php-crm-toolkit/init.php';
require_once 'config.php';
require_once 'includes/db.php';
$db = new DB();
$options = getAuth();
$serviceSettings = new Settings( $options );
$service = new OrganizationService( $serviceSettings );
$accountId = 'a2536507-018d-e711-8115-c4346bac0a5f';
// create a new contact
$contact = $service->entity( 'contact' );
$contact->accountid = $accountId;
$contact->firstname = 'Test';
$contact->lastname = 'Contact12';
$contact->jobtitle = 'Business Analyst';
$contact->mobilephone = '1002345679';
$contact->fax = '9902345679';
$contact->emailaddress1 = 'john.doe1#example.com';
$contact->address1_line1 = '119 Cambridge';
$contact->address1_line2 = 'Apt 22';
$contact->address1_city = 'Houston';
$contact->address1_stateorprovince = 'TX';
$contact->address1_postalcode = '77009';
$contact->address1_country = 'US';
$contactId = $contact->create();
echo $contactId;
?>
There is this line of your code in a question:
$contact->accountid = $accountId;
First, the parent account on a contact is saved in the parentcustomerid field that is a special lookup field that can store link to both account or contact entity.
The fields accountid and parentcontactid help to handle this in background, but are not generaly available. You need to work with parentcustomerid field.
Second, another problem when working with lookups (foreign keys) is you need to pass entity type (table name).
The correct code might look like this:
$accountRef = $client->entity( 'account' );
$accountRef->ID = $accountId;
$contact->parentcustomerid = $accountRef;
or
$contact->parentcustomerid = new EntityReference( 'account', $accountId );
Those examples are taken from the issue list, adjusted, but not tested. I hope it is working example, not functionality request.
Related
Updated to show new code / new error # 10/12/2020 11:30
I need to copy invoices from my website to xero using their API. I managed to get this working using the OAuth 1 but now need to update to OAuth2.0.
I've installed xero-php-oauth2-starter which connects and works fine with the examples. e.g. if I click the example "Create one Contact" link, the demo contact is created in xero.
As such, I know the link is working.
I've been looking around trying to find an example of how to create an invoice using the API but am finding it incredibly hard to work out.
Below is what I currently have in my xero api folder:
<?php
ini_set('display_errors', 'On');
require __DIR__ . '/vendor/autoload.php';
require_once('storage.php');
// Use this class to deserialize error caught
use XeroAPI\XeroPHP\AccountingObjectSerializer;
// Storage Classe uses sessions for storing token > extend to your DB of choice
$storage = new StorageClass();
$xeroTenantId = (string)$storage->getSession()['tenant_id'];
if ($storage->getHasExpired()) {
$provider = new \League\OAuth2\Client\Provider\GenericProvider([
'clientId' => 'REMOVED',
'clientSecret' => 'REMOVED',
'redirectUri' => 'https://REMOVED/callback.php',
'urlAuthorize' => 'https://login.xero.com/identity/connect/authorize',
'urlAccessToken' => 'https://identity.xero.com/connect/token',
'urlResourceOwnerDetails' => 'https://api.xero.com/api.xro/2.0/Organisation'
]);
$newAccessToken = $provider->getAccessToken('refresh_token', [
'refresh_token' => $storage->getRefreshToken()
]);
// Save my token, expiration and refresh token
$storage->setToken(
$newAccessToken->getToken(),
$newAccessToken->getExpires(),
$xeroTenantId,
$newAccessToken->getRefreshToken(),
$newAccessToken->getValues()["id_token"] );
}
$config = XeroAPI\XeroPHP\Configuration::getDefaultConfiguration()->setAccessToken( (string)$storage->getSession()['token'] );
$apiInstance = new XeroAPI\XeroPHP\Api\AccountingApi(
new GuzzleHttp\Client(),
$config
);
$invoices = '{"invoices":[{
"type":"Invoice.TypeEnum.ACCREC",
"contact":{"contactID":"97af3783-0f32-42be-a06d-8c586c8aa8ec"},
"lineItems":[{
"description":"Acme Tires",
"quantity":2,
"unitAmount":20,
"accountCode":"000",
"taxType":"NONE",
"lineAmount":40
}],
"date":"2019-03-11",
"dueDate":"2018-12-10",
"reference":"Website Design",
"status":"Invoice.StatusEnum.DRAFT"
}]}';
foreach ($import as $invoice) {
//create contact
$xcontact = new XeroAPI\XeroPHP\Models\Accounting\Contact();
$xcontact->setName($contactname);
//create line item
$lineItems = array();
foreach ($invoice['invoiceLineItems'] as $line) {
$newLine = new XeroAPI\XeroPHP\Models\Accounting\LineItem();
$newLine->setDescription($invoice['message']."\n".$line['description']);
$newLine->setQuantity($line['quantity']);
$newLine->setUnitAmount($line['amount']);
$newLine->setAccountCode('200');
$lineItems[] = $newLine;
}
$xinvoice = new XeroAPI\XeroPHP\Models\Accounting\Invoice();
$xinvoice->setType("ACCREC");
$xinvoice->setStatus("AUTHORISED");
$xinvoice->setDate($invoice['invoiceDate']);
$xinvoice->setDueDate($invoice['dueDate']);
$xinvoice->setLineAmountTypes("NoTax");
$xinvoice->setContact($xcontact);
$xinvoice->setLineItems($lineItems);
$xinvoice->setInvoiceNumber("INV-0".$invoice['invoiceNumber']);
$xinvoices['Invoices'][] = $xinvoice;
}
$apiResponse = $apiInstance->createInvoices($xeroTenantId,$xinvoices);
$summarize_errors = false; // bool | If false return 200 OK and mix of successfully created objects and any with validation errors
$unitdp = 4; // int | e.g. unitdp=4 – (Unit Decimal Places) You can opt in to use four decimal places for unit amounts
?>
gives
Fatal error: Uncaught InvalidArgumentException: Missing the required parameter $invoices when calling createInvoices
which I can't seem to find any details on.
I've created the product "Acme Tires" in xero just incase that was causing the issue (I remember in auth 1 that it wouldn't work if the product wasn't listed first).
Any help would be greatly appreciated.
With the new PHP SDK you need to pass an array of Invoice objects.
The following creates Invoices based on the contents of a pre-existing array ($import).
You'll see that you need to place the line items into an array, and then insert that into the invoice object. The invoice itself is then inserted into an array which is passed to the API.
<?php
foreach ($import as $invoice) {
//create contact
$xcontact = new XeroAPI\XeroPHP\Models\Accounting\Contact();
$xcontact->setName($contactname);
//create line item
$lineItems = array();
foreach ($invoice['invoiceLineItems'] as $line) {
$newLine = new XeroAPI\XeroPHP\Models\Accounting\LineItem();
$newLine->setDescription($invoice['message']."\n".$line['description']);
$newLine->setQuantity($line['quantity']);
$newLine->setUnitAmount($line['amount']);
$newLine->setAccountCode('200');
$lineItems[] = $newLine;
}
$xinvoice = new XeroAPI\XeroPHP\Models\Accounting\Invoice();
$xinvoice->setType("ACCREC");
$xinvoice->setStatus("AUTHORISED");
$xinvoice->setDate($invoice['invoiceDate']);
$xinvoice->setDueDate($invoice['dueDate']);
$xinvoice->setLineAmountTypes("NoTax");
$xinvoice->setContact($xcontact);
$xinvoice->setLineItems($lineItems);
$xinvoice->setInvoiceNumber("INV-0".$invoice['invoiceNumber']);
$xinvoices['Invoices'][] = $xinvoice;
}
$apiResponse = $apiInstance->createInvoices($xeroTenantId,$xinvoices);
?>
Update:
$apiInstance will have been created earlier eg.
$apiInstance = new XeroAPI\XeroPHP\Api\AccountingApi(
new GuzzleHttp\Client(),
$config
);
$import was an array in the original script that contained the raw data I wanted to import. You would need to replace this with your own data.
Update 2:
To use your original data, you'll need to remove the
foreach ($import as $invoice) {
loop.
and replace the references to $invoice with your own data.
For example:
//create contact
$xcontact = new XeroAPI\XeroPHP\Models\Accounting\Contact();
$xcontact->setName($contactname);
Would become:
//create contact
$xcontact = new XeroAPI\XeroPHP\Models\Accounting\Contact();
$xcontact->setContactId("97af3783-0f32-42be-a06d-8c586c8aa8ec");
Just learning Xero API (php) but I'm unsure how to proceed. The docs are pretty good in general. I've successfully created the oauth2 integration and this connects no problem (even for multiple organisations/tenants), I'm able to get the existing contacts in Xero but I now need to create a new contact (I have the name of this conteact - call her Jane Doe) i then wish to update my database record with this new Contacts contactId.
So the docs are a bit confusing but looking at the php api i think i can use:
$response = $accountingApi->setContacts( $xeroTenantId, '{"Name": "Jane Doe"}' );
would this be the right kind of approach (where $accountingApi is defined in a call earlier in the cycle and is connected)? does anyone have an example on how to add a new contact to Xero and return this new contacts contactId?
The docs don't say what (if any) response is returned after adding a new contact.
Lastly somewhat related to this, Some of my contacts are in more than one linked organisations, would these have the same clientID or will i need to somehow define one for each connected organisation?
thanks in advance
ADDITONAL
the api docs on github have this snippet:
try {
$person = new XeroAPI\XeroPHP\Models\Accounting\ContactPerson;
$person->setFirstName("John")
->setLastName("Smith")
->setEmailAddress("john.smith#24locks.com")
->setIncludeInEmails(true);
$arr_persons = [];
array_push($arr_persons, $person);
$contact = new XeroAPI\XeroPHP\Models\Accounting\Contact;
$contact->setName('FooBar')
->setFirstName("Foo")
->setLastName("Bar")
->setEmailAddress("ben.bowden#24locks.com")
->setContactPersons($arr_persons);
$arr_contacts = [];
array_push($arr_contacts, $contact);
$contacts = new XeroAPI\XeroPHP\Models\Accounting\Contacts;
$contacts->setContacts($arr_contacts);
$apiResponse = $accountingApi->createContacts($xeroTenantId,$contacts);
$message = 'New Contact Name: ' . $apiResponse->getContacts()[0]->getName();
} catch (\XeroAPI\XeroPHP\ApiException $e) {
$error = AccountingObjectSerializer::deserialize(
$e->getResponseBody(),
'\XeroAPI\XeroPHP\Models\Accounting\Error',
[]
);
$message = "ApiException - " . $error->getElements()[0]["validation_errors"][0]["message"];
}
I require only the name on Xero (all other details are in my linked App) and to obtain the contactId.
Ok so having reviewed the docs I am going with:
$contact = new XeroAPI\XeroPHP\Models\Accounting\Contact;
$contact->setName('Jane Doe');
$arr_contacts = [];
array_push($arr_contacts, $contact);
$contacts = new XeroAPI\XeroPHP\Models\Accounting\Contacts;
$contacts->setContacts($arr_contacts);
$apiResponse = $accountingApi->createContacts($xeroTenantId,$contacts);
//$message = 'New Contact Name: ' . $apiResponse->getContacts()[0]->getName();
$contactId = $apiResponse->getContacts()[0]->getContactId();
I have the following code in my controller trying to get it to work before adding validation etc
This code is from here however I will be adapting it anyway
$email = $_POST['Newsletter[email]'];
$session->save_email($email);
// Subscribe User to List
$api_key = new sammaye\mailchimp\Mailchimp(['apikey' => 'xxxxxxxxxxx']);
$list_id = "xxxxxxxxxxx";
$Mailchimp = new Mailchimp( $api_key );
$Mailchimp_Lists = new Mailchimp_Lists( $Mailchimp );
$subscriber = $Mailchimp_Lists->subscribe( $list_id, array( 'email' => $email ) );
However I get the following error (Does this mean my most data is in an array newbie)
Undefined index: Newsletter[email]
Is this something I need to set within my yii2 form so that instead of the name field being Newsletter[email] its just email?
You can do this as follows:
if (Yii::$app->request->post()) {
$data = Yii::$app->request->post();
$email = $data['NewsLetter']['email'];
}
As was already stated you can either use $_POST or the request-object.
That object encompasses everything that enters your application on startup. So yes, \Yii::$app->request->post() gives you all incoming POST-data and \Yii::$app->request->post('name') will give you a single one. Same with the get function.
However given your code that is not how you should be using Yii. The name of your variables suggests that the post is done using a model, so you might want to use that again, makes it a lot easier on validation.
If you don't have the model, it can look like so:
class Newsletter extends \yii\base\Model
{
public $email;
public function rules()
{
return array(
array('email', 'email', 'skipOnEmpty' => false)
);
}
}
The actual code in your controller could be more amongst the lines:
$request = \Yii::$app->request;
if ($request->isPost) {
$newsletter = new Newsletter;
if ($newsletter->load($request->post()) && $newsletter->validate()) {
// do your thing
}
}
It means, it is inside an array.
Try to do the following instead :
// Using isset will make sure, you don't trigger a Notice (when the variable does not exist)
$email = isset($_POST['Newsletter']['email']) ? $_POST['Newsletter']['email'] : null;
// Make sure you are receiving an email address
if ($email && filter_var($email, FILTER_VALIDATE_EMAIL))
{
$session->save_email($email);
// Subscribe User to List
$api_key = new sammaye\mailchimp\Mailchimp(['apikey' => 'xxxxxxxxxxx']);
$list_id = "xxxxxxxxxxx";
$Mailchimp = new Mailchimp( $api_key );
$Mailchimp_Lists = new Mailchimp_Lists( $Mailchimp );
$subscriber = $Mailchimp_Lists->subscribe( $list_id, array( 'email' => $email ) );
}
// Display an error message ?
else
{
// #todo
}
If the HTML form field is as below
<input name="Newsletter[email]" type="text">
then the code with in controller should be
$data = Yii::$app->request->post();
$email= $data['Newsletter']['email'];
The inline solution is:
if(is_null($email = Yii::$app->request->post('Newsletter')['email']))
throw new BadRequestHttpException('newsletter email must set');
if so if email isn't set it throws Bad Request and notice that $_POST isn't good solution when you are using a PHP framework and it's security isn't provided by framework but Yii::$app->request->post is secured by Yii.
You should simply try $_POST['Newsletter']['email'].
I have been trying to implement a program that uploads backups of my user's websites to google drive. All of them have an account on my domain, so I went through the steps of granting domain wde delegation of authority for my app as described here: https://developers.google.com/drive/delegation
Unfortunately their sample code to instantiate a drive service object fails on many levels. Here it is:
<?php
require_once "google-api-php-client/src/Google_Client.php";
require_once "google-api-php-client/src/contrib/Google_DriveService.php";
require_once "google-api-php-client/src/contrib/Google_Oauth2Service.php";
session_start();
$DRIVE_SCOPE = 'https://www.googleapis.com/auth/drive';
$SERVICE_ACCOUNT_EMAIL = '<some-id>#developer.gserviceaccount.com';
$SERVICE_ACCOUNT_PKCS12_FILE_PATH = 'privatekey.p12';
/**
* Build and returns a Drive service object
* authorized with the service accounts
* that acts on behalf of the given user.
*
* #param userEmail The email of the user.
* #return Google_DriveService service object.
*/
function buildService($userEmail) {
$key = file_get_contents(KEY_FILE);
$auth = new Google_AssertionCredentials(
SERVICE_ACCOUNT_EMAIL,
array(DRIVE_SCOPE),
$key);
$auth->setPrn($userEmail);
$client = new Google_Client();
$client->setUseObjects(true);
$client->setAssertionCredentials($auth);
return new Google_DriveService($client);
}
?>
The first obvious error is they have you set up variables but then the function uses constants. So I hardcoded in what should be there for the constants (KEY_FILE, SERVICE_ACCOUNT_EMAIL, etc) just to see if it worked and then I get the following error:
Fatal error: Call to undefined method Google_AssertionCredentials::setPrn()
Does anyone have any suggestions or comments on how to fix this? If you google these issues, google just gives page after page of links to their own documentation, which as I show above, does not work at all.
Basically I was hoping to see an example of how to use a "service account" which has been granted domain wide access to instantiate a drive service object.
It seems that there are some typos (If we wrote the doc, it should be called bug :) ) in the documentation.
<?php
require_once "google-api-php-client/src/Google_Client.php";
require_once "google-api-php-client/src/contrib/Google_DriveService.php";
require_once "google-api-php-client/src/contrib/Google_Oauth2Service.php";
session_start();
function buildService($userEmail) {
$DRIVE_SCOPE = 'https://www.googleapis.com/auth/drive';
$SERVICE_ACCOUNT_EMAIL = '<some-id>#developer.gserviceaccount.com';
$SERVICE_ACCOUNT_PKCS12_FILE_PATH = 'privatekey.p12';
$key = file_get_contents($SERVICE_ACCOUNT_PKCS12_FILE_PATH);
$auth = new Google_AssertionCredentials($SERVICE_ACCOUNT_EMAIL, array($DRIVE_SCOPE), $key); // Changed!
$auth->prn = $userEmail; // Changed!
$client = new Google_Client();
$client->setUseObjects(true);
$client->setAssertionCredentials($auth);
return new Google_DriveService($client);
}
$service = buildService('email#yourdomain.com');
$file = new Google_DriveFile();
$file->setTitle('My document');
$file->setDescription('A test document');
$file->setMimeType('text/plain');
$data = "contents";
$createdFile = $service->files->insert($file, array('data' => $data,'mimeType' =>'text/plain',));
print_r($createdFile);
They defined three varivbales but used three three constants- Removed the contsnts and used the variables instead.
There is no method Google_AssertionCredentials::setPrn(). The property prn's visibility is public. So you can set it as $auth->prn = $userEmail;
Can somebody provide working example of using the Bigquery API with PHP. I see there are examples for python and java but could not find anything for PHP.
Here is the bigquery browser https://bigquery.cloud.google.com/?pli=1
For e.g You can run this SQL in the browser
SELECT corpus,count(*) FROM publicdata:samples.shakespeare
group by corpus limit 5;
I want to simulate similar call via PHP.
Even a rough example of how to use the PHP API will help a lot.
Use the Google API Client for PHP. Here's a simple example of a script that does a single synchronous query job. This uses the class names found in the downloadable API client. Note: the source pulled from SVN features different class names. Note where you must add your own values for client secret, client id, redirect URI, and project id.
<?php
require_once 'google-api-php-client/src/apiClient.php';
require_once 'google-api-php-client/src/contrib/apiBigqueryService.php';
session_start();
$client = new apiClient();
// Visit https://developers.google.com/console to generate your
// oauth2_client_id, oauth2_client_secret, and to register your oauth2_redirect_uri.
$client->setClientId('XXXXXXXXXXXXXXX.apps.googleusercontent.com');
$client->setClientSecret('XXXXXXXXXXXXXXXXXXX');
$client->setRedirectUri('http://www_your_domain.com/somescript.php');
// Your project id
$project_id = 'XXXXXXXXXXXXXXXXXXXX';
// Instantiate a new BigQuery Client
$bigqueryService = new apiBigqueryService($client);
if (isset($_REQUEST['logout'])) {
unset($_SESSION['access_token']);
}
if (isset($_SESSION['access_token'])) {
$client->setAccessToken($_SESSION['access_token']);
} else {
$client->setAccessToken($client->authenticate());
$_SESSION['access_token'] = $client->getAccessToken();
}
if (isset($_GET['code'])) {
$redirect = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];
header('Location: ' . filter_var($redirect, FILTER_SANITIZE_URL));
}
?>
<!doctype html>
<html>
<head>
<title>BigQuery API Sample</title>
</head>
<body>
<div id='container'>
<div id='top'><h1>BigQuery API Sample</h1></div>
<div id='main'>
<?php
$query = new QueryRequest();
$query->setQuery('SELECT TOP( title, 10) as title, COUNT(*) as revision_count FROM [publicdata:samples.wikipedia] WHERE wp_namespace = 0;');
$jobs = $bigqueryService->jobs;
$response = $jobs->query($project_id, $query);
// Do something with the BigQuery API $response data
print_r($response);
?>
</div>
</div>
</body>
</html>
The previous answers have outdated code. The following example should work with the more recent API (https://github.com/google/google-api-php-client/blob/master/src/Google/Service/Bigquery.php) :
require_once '../source/application/libraries/Google/autoload.php';
public function createGClient(){
define("CLIENT_ID", "{PROJECT_ID}.apps.googleusercontent.com");
define("SERVICE_ACCOUNT_NAME","{SERVICE_ACCOUNT EMAIL FROM CONSOLE}");
define("KEY_FILE",'../{FILENAME}.p12');
define("PROJECT_ID","{PROJECT_ID}");
define("DATASET_ID","{DATASET_ID}");
define("TABLE_ID","");
$this->client = new Google_Client();
$this->client->setApplicationName("{NAME}");
$key = file_get_contents(KEY_FILE);
$this->client->setAssertionCredentials(new Google_Auth_AssertionCredentials(SERVICE_ACCOUNT_NAME, array('https://www.googleapis.com/auth/bigquery'), $key, "notasecret"));
$this->client->setClientId(CLIENT_ID);
$this->service = new Google_Service_Bigquery($this->client);
}
public function runQuery(){
// To see the a list of tables
print_r($this->service->tables->listTables(PROJECT_ID, DATASET_ID));
// To see details of a table
print_r($this->service->tables->get(PROJECT_ID, DATASET_ID, TABLE_ID));
// To query a table
$jobs = $this->service->jobs;
$query = new Google_Service_Bigquery_QueryRequest();
$query->setQuery("SELECT * FROM wherever;");
$response = $jobs->query(PROJECT_ID, $query);
print_r($response);
}
This is a modified version of the sample given at: http://michaelheap.com/using-the-php-sdk-with-google-bigquery/ for a service account. To use a client account you would need to use oauth2 and have a pingback address.
I had a lot of issues finding examples.
This is a basic async query, but can demonstrate current PHP API usage, you can see the Python/Java example of the API for async queries here: https://developers.google.com/bigquery/querying-data
Please note, I am not referencing how to setup $client credentials, as it is well documented elsewhere.
$bq = new Google_BigqueryService($client);
//build query
$sql = 'select * from example.table LIMIT 10';
$job = new Google_Job();
$config = new Google_JobConfiguration();
$queryConfig = new Google_JobConfigurationQuery();
$config->setQuery($queryConfig);
$job->setConfiguration($config);
$queryConfig->setQuery($sql);
$insert = new Google_Job($bq->jobs->insert(PROJECT_ID,$job));
$jr = $insert->getJobReference();
$jobId = $jr['jobId'];
$res = new Google_GetQueryResultsResponse($bq->jobs->getQueryResults(PROJECT_ID, $jobId));
//see the results made it as an object ok:
var_dump($results);
/**
* Executes and returns bigQuery response with 'INTERACTIVE' priority
* $this->service is the object of Google_Service_Bigquery
* $this->service = new Google_Service_Bigquery($this->client);
* #param String $sql
* #return Google_Service_Bigquery_GetQueryResultsResponse
*/
public function execute($sql) {
$job = new Google_Service_Bigquery_Job();
$config = new Google_Service_Bigquery_JobConfiguration();
$queryConfig = new Google_Service_Bigquery_JobConfigurationQuery();
$queryConfig->setQuery($sql);
/**
* Priority is set to INTERACTIVE for faster response options are 'BATCH'/'INTERACTIVE'
*/
$queryConfig->setPriority("INTERACTIVE");
$config->setQuery($queryConfig);
$job->setId(md5("$sql_{microtime()}"));
$job->setConfiguration($config);
$running = $this->service->jobs->insert('divine-builder-586', $job);
/* #var $running Google_Service_Bigquery_Job */
$jr = $running->getJobReference();
$jobId = $jr['jobId'];
$res = $this->service->jobs->getQueryResults('divine-builder-586', $jobId);
/* #var $res Google_Service_Bigquery_GetQueryResultsResponse */
return $res;
}