I'm using google sheet api with this logic for each request:
create a sheet,
add custom query there (custom formula),
fecth query results,
delete the created sheet.
The creation code is a follow with Laravel:
class GoogleSheetsApiClientManager {
private $client;//authorized API client.
private $service = null;
public function __construct($apiOptions) {
$this->client = new Google_Client();
$this->client->setApplicationName(array_get($apiOptions, 'application_name', 'Google Sheets API PHP'));
$this->client->setScopes(array_get($apiOptions, 'scope', Google_Service_Sheets::SPREADSHEETS));
$this->client->setAuthConfig(array_get($apiOptions, 'credential_path'));
$this->client->setAccessType('offline');
$this->service = new Google_Service_Sheets($this->client);
}
public function addNewSheet($spreadsheetId, $hidden = false, $sheetName = false){
try {
$properties = [
'hidden' => $hidden
];
if($sheetName){
$properties['title'] = $sheetName;
}
$body = new Google_Service_Sheets_BatchUpdateSpreadsheetRequest([
'requests' => [
'addSheet' => [
'properties' => $properties
]
]
]);
$result = $this->service->spreadsheets->batchUpdate($spreadsheetId, $body);
return $result;
}
catch (\Exception $exception) {
Log::error('Add new sheet using Google Sheet API : '.$exception->getMessage());
return false;
}
}
}
And the call is like:
$apiOptions = [
'application_name' => 'My app name',
'credential_path' => __DIR__.'/service_account-secret.json'
];
$googleSheetManager = new GoogleSheetsApiClientManager($apiOptions);
$spreadsheetId = '--theSpreasheetId--';
$mySheet = $googleSheetManager->addNewSheet($spreadsheetId);
The issue : Each time I create new sheet, its name is based on last created one. eg: last sheet name is sheet5, even sheet5 has been deleted I got new sheet with name sheet6.
What I would like to have is the minimal possible name, meaning if sheet5 & sheet4 are not there (but sheet3 is present), I would like a new name sheet4, not an endless incremented name
Related
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.
I am trying to add and update using the same API, currently, I can add but I am not clear about how to update using the same API.
I am adding folders against id and my body response looks like this:
{
"id": "2",
"folder_detail": [1,3,4]
}
I can add folders with id 1,3 and 4 against id 2 but next time when I hit the same API with folder[1,3,5] it should update folders details not should add again, I can do that by making separate API but I want to do that in one API.
My Controller code:
try {
$folder = Doctor::where('id', $request->get('id'))->first();
$folder->doctor()->attach($request->get('folder_detail', []));
DB::commit();
return response([
'status' => true,
'message' => 'Folder detail added',
], 200);
} catch (\Exception $ex) {
DB::rollback();
return response([
'status' => false,
'message' => __('messages.validation_errors'),
'errors' => $ex->getMessage(),
], 500);
}
}
public function doctor()
{
return $this->belongsToMany('App\Folder', 'folder_details');
}
Your help will be highly appreciated?
Okay so after our back and forth in the comments I think you are looking for something like this:
$folders = $request->get('folder_detail', []);
foreach($folders as $folder) {
$record = Folder::firstOrNew(['id', $folder]);
$record->doctor_id = $request->id;
// You can add your own records here, or use the 'fill' function
}
So, this way, you loop through all your folders. Check if the folder with the specific ID already exists, if it does not, it creates a new one. The doctor is linked through the doctor_id on your record.
Find record if exist then update otherwise create
$post = $request->all();
$doctor = Doctor::find($post['id']);
if($doctor){
$doctor->update([
//your data for update doctor model
]);
//remove old folders which is related with this doctor
Folder::where('doctor_id', $doctor->id)->delete();
//add current data of folder
if(!empty($post['folder_detail'])){
foreach($post['folder_detail'] as $folder){
Folder::create([
'doctor_id' => $doctor->id,
'folder_detail' => $folder
]);
}
}
//return your response here
} else {
$doctor = Doctor::create([
//data for create doctore
]);
//add current data of folder
if(!empty($post['folder_detail'])){
foreach($post['folder_detail'] as $folder){
Folder::create([
'doctor_id' => $doctor->id,
'folder_detail' => $folder
]);
}
}
//return your response here
}
I have table which have multiple reference to ohter tables like
user
id name email
categories
id title
user_categories
user_id category_id
Here a user will have multiple category associated with him/her
I am able to save these successfully with new records like following
View File:
echo $form->field($package_categories, 'category_id')->dropDownList( ArrayHelper::map(
StudyMaterialCategories::find()->all(), 'id', 'title'),
['multiple' => true]
);
Save New record:
$model = new Packages();
$package_categories = new PackageCategories();
$request = Yii::$app->request;
if ($request->isPost) {
$transaction = Yii::$app->db->beginTransaction();
try {
$post = $request->post();
$model->load($post);
$model->save();
foreach ($post['PackageCategories']['category_id'] as $key => $value) {
$package_categories = new PackageCategories();
$package_categories->category_id = $value;
$package_categories->package_id = $model->id;
$package_categories->save();
}
$transaction->commit();
return $this->redirect(['view', 'id' => $model->id]);
} catch (Exception $ex) {
$transaction->rolback();
Yii::$app->session->setFlash("error", $ex->getMessage());
}
}
Till now It's running successfully.
But I'm stuck when going to update the table. The problem part is dropdown list. How to set multiple selected option as per database if I'm coming with array of object.
Have a look on the following code
$package_categories = PackageCategories::find()
->where('package_id=:package_id', ['package_id' => $id])->all();
if (count($package_categories) < 1) {
$package_categories = new PackageCategories();
}
$request = Yii::$app->request;
if ($request->isPost) {
$transaction = Yii::$app->db->beginTransaction();
try {
$post = $request->post();
$model->load($post);
$model->save();
$package_categories = new PackageCategories();
$package_categories->deleteAll(
"package_id=:package_id",
[':package_id' => $model->id]
);
foreach ($post['PackageCategories']['category_id'] as $key => $value) {
$package_categories = new PackageCategories();
$package_categories->category_id = $value;
$package_categories->package_id = $model->id;
$package_categories->save();
}
$transaction->commit();
return $this->redirect(['view', 'id' => $model->id]);
} catch (Exception $ex) {
$transaction->rolback();
Yii::$app->session->setFlash("error", $ex->getMessage());
}
}
if I try to get first object of the array $package_categories of only able to set selected one option
This is an example code of a model class Permit which has a many to many relationship with Activity through PermitActivity (pivot table model).
Model Class Activity
public class Permit extends \yii\db\ActiveRecord {
public $activities_ids;
...
public function rules() {
return [
...
[['activities_ids'], 'safe'],
...
];
}
...
// Method called after record is saved, be it insert or update.
public function afterSave($insert, $changedAttributes) {
// If this is not a new record, unlink all records related through relationship 'activities'
if(!$this->isNewRecord) {
// We unlink all related records from the 'activities' relationship.
$this->unlinkAll('activities', true);
// NOTE: because this is a many to many relationship, we send 'true' as second parameter
// so the records in the pivot table are deleted. However on a one to many relationship
// if we send true, this method will delete the records on the related table. Because of this,
// send false on one to many relationships if you don't want the related records deleted.
}
foreach($this->activities_ids as $activity_id) {
// Find and link every model from the array of ids we got from the user.
$activity = Activity::findOne($activity_id);
$this->link('activities', $activity);
}
parent::afterSave($insert, $changedAttributes);
}
...
// Declare relationship with Activity through the pivot table permitActivity
public function getActivities(){
return $this->hasMany(Activitiy::className(), ['id' => 'activity_id'])
->viaTable('permitActivity',['permit_id' => 'id']);
}
...
public function afterFind(){
parent::afterFind();
$this->activities_id = ArrayHelper::getColumn($this->activities, 'id');
}
}
This way the model class is the one responsible for creating and updating the relationship using the pivot table.
The most important thing is to have the relationship method declared correctly.
Edit
This is an example of the view using kartikv\widgets\Select2. I don't really know if dropDownList supports multiple select, however Select2 has so many useful features i usually use it over other options.
echo $form->field($model, 'activities')->widget(Select2::classname(), [
'data' => $data,
'options' => [
'placeholder' => '...'
],
'pluginOptions' => [
'allowClear' => true,
'multiple' => true,
],
]);
I am working on Joomla 3.6 and I am very new in joomla. I am fetching the data from an api and I want to pass that data to a view. How can I do that.
Controler: user.php
public function profile() {
$wskey = sdafsda;
$companycode = 'sdafsd';
$client = 1;
$cardno = 'sdafsd';
$pin = 'sdaf';
$wsdl = 'http://example/service.asmx?wsdl';
$getdata = array(
'WSKey' => $wskey,
'CompanyCode' => $companycode,
'CardNo' => $this->EncryptData($cardno),
'Client' => $client,
'PIN' => $this->EncryptData($pin),
);
$soapClient = new SoapClient($wsdl);
try {
$result = $soapClient->GetProfile($getdata);
} catch (Exception $e) {
return $e;
}
}
And view is created in com_users->views->cprofile.
I want to show this data in default.php of cprofile views and Want to know how can I call a view with data.
Sorry might not be clear.
I'm currently working on a project using the Phalcon Framework that has pages with complex forms and a lot of inputs, to break it down nicely I'm dividing the forms into a step-by-step process.
How would one validate the form on each step before going to the next step and then save the whole form on the final step?
I can't seem to find anything documented about this sort of process as it likes to validate the form in it's entirety if I use the form builder.
Simple, just create a custom methods in your form class to validate any step, and the posted data from some step save into message class and store it into session by "stepX", when posted data is not valid just set defaults from post. When valid save it into session as i describe above.
For example how i mean "controller"
<?php
class MyController extends BaseController {
public function processStep1Action(){
$form = new MyForm();
if($this->request->isPost()){//im using my custom request class
if(!$form->isValid($this->request->getPost()){
//error messages goes here
$form->setDefaultsFromRequest($this->request); // it will set the filled data
}
else {
$messageClass = new MyMessageContainer();
$messageClass->setData($this->request);//inside parse requested data into message class, or parse it as $messageClass->name = $this->request->getPost('name');
$this->session->save('step1',$messageClass); //maybe it would be want to serialize it
//then redirect to the step 2 or x
}
}
}
}
So in the next step you can access data from sessions $this->session->get('step1'); so you can in final step load all posted data and store it into DB.
I hope this helps! :)
here is my form maybe it can be helpful for you.
<?php
namespace Manager\Library\Forms\User;
use Phalcon\Forms\Form,
Phalcon\Forms\Element\Email,
Phalcon\Forms\Element\Select,
Phalcon\Forms\Element\Password,
Phalcon\Forms\Element\Check,
Phalcon\Validation\Validator\Confirmation,
Phalcon\Validation\Validator\StringLength,
Phalcon\Forms\Element\Submit,
Phalcon\Validation\Validator\PresenceOf,
Model\Group;
class AddUser extends Form {
public function initialize()
{
$email = new Email('email');
$email->addValidators(array(
new \Phalcon\Validation\Validator\Email(array(
'message' => 'Nezadali jste email nebo má nesprávny tvar(email#domena.tld).'
))
));
$this->add($email);
$this->initGroupElement();
$password = new Password('password');
$password
->addValidator(new StringLength(array('min' => 6,'messageMinimum' => 'Nezadali jste heslo nebo je příliš krátke, minimální počet znaků je 6.')))
->addValidator(new Confirmation(array('with' => 'password-again',"message" => "Zadané hesla se neshodují.")));
$this->add($password);
$repeatPassword = new Password('password-again');
$this->add($repeatPassword);
$this->initializeProfileElements();
$active = new Check('active',array('value' => 1));
$this->add($active);
$this->add( new Submit('save') );
\Phalcon\Tag::setDefault('password', '');
\Phalcon\Tag::setDefault('password-again', '');
}
public function initializeEdit(){
$email = new Email('email');
$email->addValidators(array(
new \Phalcon\Validation\Validator\Email(array(
'message' => 'Nezadali jste email nebo má nesprávny tvar(email#domena.tld).'
))
));
$this->add($email);
$this->initGroupElement();
$password = new Password('password');
$this->add($password);
$repeatPassword = new Password('password-again');
$this->add($repeatPassword);
$this->initializeProfileElements();
$active = new Check('active',array('value' => 1));
$this->add($active);
$this->add( new Submit('save') );
\Phalcon\Tag::setDefault('password', '');
\Phalcon\Tag::setDefault('password-again', '');
}
protected function initGroupElement(){
$auth = \Core\Auth::getIdentity();
$groups = new Group();
// $groups->addColumns(array('id','name'));
//set global condition about Super Admin
$groups->addFilter('id', 1,'<>');
if($auth){
//set restrictions for main groups
if((int)$auth->group_id === 1){ //super admingroup
//no filter
}
else if((int)$auth->group_id === 2){ //admin group
$groups->addFilter('id', 1,'>');
}
else if((int)$auth->group_id === 6){//Provozovatel group
$groups->addFilter('id',array(3,6,7));
$groups->addFilter('public', 1,'=',true);
}
else { // other groups
$groups->addFilter('public', 1);
}
}
$groups = $groups->findFiltered();
$groupElement = new Select('group');
foreach($groups as $group){
$groupElement->addOption(array($group->id => $group->name));
}
$this->add($groupElement);
}
protected function initializeProfileElements(){
$forename = new \Phalcon\Forms\Element\Text('forename');
$this->add($forename);
$surname = new \Phalcon\Forms\Element\Text('surname');
$this->add($surname);
$street = new \Phalcon\Forms\Element\Text('street');
$this->add($street);
$postal = new \Phalcon\Forms\Element\Text('postal');
$this->add($postal);
$city = new \Phalcon\Forms\Element\Text('city');
$this->add($city);
$ic = new \Phalcon\Forms\Element\Text('ic');
$this->add($ic);
$dic = new \Phalcon\Forms\Element\Text('dic');
$this->add($dic);
}
public function setDefault($fieldName,$value){
\Phalcon\Tag::setDefault($fieldName, $value);
}
public function setDefaults($object){
if($object instanceof \Model\User){
$this->setDefaultsFromObject($object);
}
else if($object instanceof \Phalcon\Http\Request){
$this->setDefaultsFromRequest($object);
}
}
protected function setDefaultsFromObject(\Model\User $user){
$profile = $user->getRelated('\Model\Profile');
\Phalcon\Tag::setDefaults(array(
'email' => $user->email,
'group' => $user->group_id,
'active' => $user->active,
'forename' => $profile->forename,
'surname' => $profile->surname,
'street' => $profile->street,
'city' => $profile->city,
'postal' => $profile->postal,
'ic' => $profile->IC,
'dic' => $profile->DIC
));
}
protected function setDefaultsFromRequest(\Phalcon\Http\Request $request){
\Phalcon\Tag::setDefaults(array(
'email' => $request->getPost('email'),
'group' => $request->getPost('group'),
'active' => $request->getPost('active')
));
\Phalcon\Tag::setDefaults(array(
'forename' => $request->getPost('forename'),
'surname' => $request->getPost('surname'),
'street' => $request->getPost('street'),
'city' => $request->getPost('city'),
'postal' => $request->getPost('postal'),
'ic' => $request->getPost('ic'),
'dic' => $request->getPost('dic')
));
}
}
In addition to Kamil's answer, another option to consider is to use Javascript on the front-end to handle your multi-step form. This will add some complexity as you will need to have the javascript to handle the form steps and do preliminary validation, but it only requires a single submit where you can validate content within a single method.