diff --git a/.gitignore b/.gitignore index 987e2a2..02b18bd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ composer.lock vendor +credentials +local.env diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..9649ce0 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 SIL International + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..8212f92 --- /dev/null +++ b/README.md @@ -0,0 +1,49 @@ +# Google Sheets PHP + +A simple library for pushing data to a Google Sheet using the Google PHP API +Client **version 1**. + +## Authorization + +To use this library to push data to a Google Sheet... + +1. Go to the Google Developers Console. +2. If you do not yet have a project that you plan to use this with, create one. +3. Enable the "Google Sheets API" for that project. +4. Create credentials for the project: + - To use the Google Sheets API + - From a web server + - To access application data + - Not using Google App Engine or Computer Engine + - Give it a service account name + - Don't give it a role + - Select the JSON key option +5. Save that JSON file to some private folder where your code can access it. +6. Get the Spreadsheet ID of the Google Sheet that you want to push data to. It + is shown in its URL after the "https://docs.google.com/spreadsheets/d/" + prefix, up until the next "/". +7. Share that Google Sheet (cf. the spreadsheet ID) with the `client_email` + value found in your Google credentials JSON file, giving it permission to + edit the spreadsheet. + +Viola! You should now be able to push data to that Google Sheet. + +## Testing + +To test this library (and that your permissions are set up correctly)... + +1. Clone this repo to your local machine. +2. Put your JSON credentials file in the "credentials" folder (Git is set to + ignore that folder's contents... DO NOT COMMIT YOUR JSON FILE TO GIT). +3. Copy the `local.env.dist` file to `local.env`, giving it the requested + values. +4. Open a terminal to the root of the repo and run `make`. +5. Look at your Google Sheet and verify that data has been appended. + +## Resources + +How to use the Google PHP API Client (v1) that this uses: +- https://github.com/googleapis/google-api-php-client/blob/v1.1.8/examples/service-account.php + +Documentation on the `append` Google Sheets API: +- https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets.values/append diff --git a/features/behat.yml b/behat.yml similarity index 63% rename from features/behat.yml rename to behat.yml index 13b8229..4ff545e 100644 --- a/features/behat.yml +++ b/behat.yml @@ -1,5 +1,5 @@ default: suites: google_sheets: - paths: [ "%paths.base%/google-sheets.feature" ] + paths: [ "%paths.base%/features/google-sheets.feature" ] contexts: [ Sil\GoogleSheets\features\context\GoogleSheetsContext ] diff --git a/composer.json b/composer.json index 51e5951..2a9ff7c 100644 --- a/composer.json +++ b/composer.json @@ -7,7 +7,8 @@ }, "require-dev": { "behat/behat": "^3.6", - "roave/security-advisories": "dev-master" + "roave/security-advisories": "dev-master", + "silinternational/php-env": "^2.1" }, "autoload": { "psr-4": { diff --git a/credentials/.gitkeep b/credentials/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/docker-compose.yml b/docker-compose.yml index b7f3edb..b40294b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,9 @@ version: '2' services: - cli: + test: image: silintl/php7:7.2 + env_file: + - local.env volumes: - ./:/data/ working_dir: /data diff --git a/features/context/GoogleSheetsContext.php b/features/context/GoogleSheetsContext.php new file mode 100644 index 0000000..fc1e5cd --- /dev/null +++ b/features/context/GoogleSheetsContext.php @@ -0,0 +1,37 @@ +googleSheets = new GoogleSheets( + 'Sil\GoogleSheets library', + __DIR__ . '/../../' . $jsonAuthFilePath + ); + } + + /** + * @When I append data to a Google Sheet + */ + public function iAppendDataToAGoogleSheet() + { + $spreadsheetId = Env::requireEnv('TEST_SPREADSHEET_ID'); + $this->googleSheets->append( + [ + ['The', 'first', 'row'], + ['The', 'second', 'row'], + ], + $spreadsheetId + ); + } +} diff --git a/features/google-sheets.feature b/features/google-sheets.feature new file mode 100644 index 0000000..30e0b5d --- /dev/null +++ b/features/google-sheets.feature @@ -0,0 +1,5 @@ +Feature: Interacting with Google Sheets + + Scenario: Appending data to a Google Sheet + When I append data to a Google Sheet + # Note: The test will fail if an exception is thrown diff --git a/local.env.dist b/local.env.dist new file mode 100644 index 0000000..11c56cc --- /dev/null +++ b/local.env.dist @@ -0,0 +1,7 @@ +# The path (relative to the repo's root) to the Google credentials JSON file to +# use for testing. +TEST_JSON_AUTH_FILE_PATH=credentials/your-credentials-file-name.json + +# The ID of the Google Sheet, shown in its URL after the +# "https://docs.google.com/spreadsheets/d/" prefix, up until the next "/". +TEST_SPREADSHEET_ID= diff --git a/src/GoogleSheets.php b/src/GoogleSheets.php index ac7cfc8..ea624a6 100644 --- a/src/GoogleSheets.php +++ b/src/GoogleSheets.php @@ -27,20 +27,24 @@ public function __construct( Assert::isNotEmpty($applicationName, 'applicationName'); Assert::fileExists($jsonAuthFilePath); - $jsonAuthString = \file_get_contents($jsonAuthFilePath); - $credentials = json_decode($jsonAuthString, true); $googleClient = new Google_Client(); - $googleClient->setApplicationName($applicationName); - $googleClient->setScopes($scopes); - $googleClient->setAuthConfig($credentials); - $googleClient->setAccessType('offline'); + $assertionCredentials = $googleClient->loadServiceAccountJson( + $jsonAuthFilePath, + $scopes + ); + $googleClient->setAssertionCredentials($assertionCredentials); $this->sheets = new Google_Service_Sheets($googleClient); } /** * Append the provided data to the specified Google Sheet. * - * @param array $data + * @param array[] $data A nested array, where the inner arrays' entries will + * go into consecutive cells in a given row. Example: + * [ + * ['The', 'first', 'row'], + * ['The', 'second', 'row'], + * ] * @param string $spreadsheetId The Spreadsheet ID * @param string $tabName The name of the tab within the Google Sheet */ @@ -51,17 +55,20 @@ public function append( ) { Assert::isNotEmpty($spreadsheetId, 'Spreadsheet ID'); - $range = sprintf('%s!A1:A1000', $tabName); + $range = sprintf('%s!A:A', $tabName); $postBody = new Google_Service_Sheets_ValueRange([ 'range' => $range, - 'majorDimension' => 'COLUMNS', - 'values' => [$data], + 'majorDimension' => 'ROWS', + 'values' => $data, ]); $this->sheets->spreadsheets_values->append( $spreadsheetId, $range, $postBody, - ['valueInputOption' => 'USER_ENTERED'] + [ + 'valueInputOption' => 'USER_ENTERED', + 'insertDataOption' => 'INSERT_ROWS', + ] ); } }