Skip to content

Commit 390be3d

Browse files
committed
feat: add sqlserver sample
1 parent 8e3b542 commit 390be3d

File tree

6 files changed

+363
-0
lines changed

6 files changed

+363
-0
lines changed

cloud_sql/sqlserver/pdo/README.md

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Connection to Cloud SQL - SQL Server
2+
3+
## Before you begin
4+
5+
1. This code sample requires the `pdo_sqlsrv` extension to be installed and enabled. For more information, including getting started guides, refer to the [source repository](https://github.com/Microsoft/msphpsql).
6+
2. Before you use this code sample, you need to have [Composer](https://getcomposer.org/) installed or downloaded into this folder. Download instructions can be found [here](https://getcomposer.org/download/).
7+
3. Create a SQL Server Cloud SQL Instance by following these [instructions](https://cloud.google.com/sql/docs/sqlserver/create-instance). Note the connection string, database user, and database password that you create.
8+
4. Create a database for your application by following these [instructions](https://cloud.google.com/sql/docs/sqlserver/create-manage-databases). Note the database name.
9+
5. Create a service account with the 'Cloud SQL Client' permissions by following these [instructions](https://cloud.google.com/sql/docs/postgres/connect-external-app#4_if_required_by_your_authentication_method_create_a_service_account). Download a JSON key to use to authenticate your connection.
10+
6. Use the information noted in the previous steps:
11+
12+
```bash
13+
export GOOGLE_APPLICATION_CREDENTIALS=/path/to/service/account/key.json
14+
export CLOUD_SQL_CONNECTION_NAME='<MY-PROJECT>:<INSTANCE-REGION>:<MY-DATABASE>'
15+
export DB_USER='my-db-user'
16+
export DB_PASS='my-db-pass'
17+
export DB_NAME='my-db-name'
18+
export DB_HOSTNAME='localhost'
19+
```
20+
21+
Note: Saving credentials in environment variables is convenient, but not secure - consider a more secure solution such as [Cloud KMS](https://cloud.google.com/kms/) to help keep secrets safe.
22+
23+
## Running Locally
24+
25+
To run this application locally, download and install the `cloud_sql_proxy` by following the instructions [here](https://cloud.google.com/sql/docs/sqlserver/sql-proxy#install).
26+
27+
Once the proxy is ready, use the following command to start the proxy in the background:
28+
29+
```bash
30+
$ ./cloud_sql_proxy -dir=/cloudsql \
31+
--instances=$CLOUD_SQL_CONNECTION_NAME=tcp:1433 \
32+
--credential_file=$GOOGLE_APPLICATION_CREDENTIALS
33+
```
34+
35+
Note: Make sure to run the command under a user with write access in the `/cloudsql` directory. This proxy will use this folder to create a unix socket the application will use to connect to Cloud SQL.
36+
37+
Execute the following:
38+
39+
```bash
40+
$ php -S localhost:8080
41+
```
42+
43+
Navigate towards http://localhost:8080 to verify your application is running correctly.
44+
45+
## Google App Engine Standard
46+
47+
To run on GAE-Standard, create an App Engine project by following the setup for these [instructions](https://cloud.google.com/appengine/docs/standard/php7/quickstart#before-you-begin).
48+
49+
First, update `app.yaml` with the correct values to pass the environment variables into the runtime.
50+
51+
Next, the following command will deploy the application to your Google Cloud project:
52+
53+
```bash
54+
$ gcloud app deploy
55+
```

cloud_sql/sqlserver/pdo/app.yaml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Copyright 2020 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
runtime: php72
16+
17+
# Remember - storing secrets in plaintext is potentially unsafe. Consider using
18+
# something like https://cloud.google.com/kms/ to help keep secrets secret.
19+
env_variables:
20+
CLOUD_SQL_CONNECTION_NAME: <MY-PROJECT>:<INSTANCE-REGION>:<MY-DATABASE>
21+
DB_USER: my-db-user
22+
DB_PASS: my-db-pass
23+
DB_NAME: my_db
24+
25+
# Defaults to "serve index.php" and "serve public/index.php". Can be used to
26+
# serve a custom PHP front controller (e.g. "serve backend/index.php") or to
27+
# run a long-running PHP script as a worker process (e.g. "php worker.php").
28+
#
29+
# entrypoint: serve index.php

cloud_sql/sqlserver/pdo/index.php

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
/*
3+
* Copyright 2020 Google LLC.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
require_once 'src/DB.php';
19+
require_once 'src/Votes.php';
20+
21+
use Google\Cloud\Samples\CloudSQL\SQLServer\DB;
22+
use Google\Cloud\Samples\CloudSQL\SQLServer\Votes;
23+
24+
$votes = new Votes(DB::createPdoConnection());
25+
26+
if ($_SERVER['REQUEST_URI'] == '/' && $_SERVER['REQUEST_METHOD'] == 'GET') {
27+
$list = $votes->list();
28+
29+
$vote_count = $votes->count_candidates();
30+
$tab_count = $vote_count['tabs'];
31+
$space_count = $vote_count['spaces'];
32+
33+
include_once("./template.php");
34+
} elseif ($_SERVER['REQUEST_URI'] == '/' && $_SERVER['REQUEST_METHOD'] == 'POST') {
35+
$message = 'Invalid vote. Choose Between TABS and SPACES';
36+
37+
if (!empty($_POST['team']) && in_array($_POST['team'], ['SPACES', 'TABS'])) {
38+
$message = $votes->save($_POST['team']);
39+
}
40+
41+
echo $message;
42+
}

cloud_sql/sqlserver/pdo/src/DB.php

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
/*
3+
* Copyright 2020 Google LLC.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
namespace Google\Cloud\Samples\CloudSQL\SQLServer;
19+
20+
use PDO;
21+
22+
class DB
23+
{
24+
public static function createPdoConnection()
25+
{
26+
$username = getenv("DB_USER");
27+
$password = getenv("DB_PASS");
28+
$schema = getenv("DB_NAME");
29+
$hostname = getenv("DB_HOSTNAME") ?: "(local)";
30+
31+
# [START cloud_sql_sqlserver_pdo_create]
32+
// $username = 'your_db_user';
33+
// $password = 'yoursupersecretpassword';
34+
// $schema = 'your_db_name';
35+
36+
$dsn = sprintf('sqlsrv:server=(local);Database=%s', $schema, $hostname);
37+
38+
return new PDO($dsn, $username, $password);
39+
# [END cloud_sql_sqlserver_pdo_create]
40+
}
41+
}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
<?php
2+
/*
3+
* Copyright 2020 Google LLC.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
namespace Google\Cloud\Samples\CloudSQL\SQLServer;
19+
20+
use PDO;
21+
22+
class Votes
23+
{
24+
private $connection;
25+
26+
public function __construct(PDO $connection)
27+
{
28+
$this->connection = $connection;
29+
$this->create_table();
30+
}
31+
32+
private function create_table()
33+
{
34+
$tableName = "votes";
35+
36+
$existsStmt = "SELECT * FROM INFORMATION_SCHEMA.TABLES
37+
WHERE TABLE_NAME = ?";
38+
39+
$stmt = $this->connection->prepare($existsStmt);
40+
$stmt->execute([$tableName]);
41+
42+
// If table does not exist, create it!
43+
$row = $stmt->fetch(PDO::FETCH_ASSOC);
44+
if (!$row) {
45+
$sql = "
46+
CREATE TABLE votes (
47+
vote_id INT NOT NULL IDENTITY,
48+
time_cast DATETIME NOT NULL,
49+
candidate VARCHAR(6) NOT NULL,
50+
PRIMARY KEY (vote_id)
51+
);";
52+
if ($this->connection->exec($sql) !== 1) {
53+
print_r($this->connection->errorInfo());
54+
exit;
55+
}
56+
}
57+
}
58+
59+
public function list()
60+
{
61+
$sql = "SELECT TOP 5 candidate, time_cast FROM votes ORDER BY time_cast DESC";
62+
$statement = $this->connection->prepare($sql);
63+
$statement->execute();
64+
return $statement->fetchAll();
65+
}
66+
67+
public function count_candidates()
68+
{
69+
$sql = "SELECT COUNT(vote_id) as voteCount FROM votes WHERE candidate = ?";
70+
$count = [];
71+
72+
$statement = $this->connection->prepare($sql);
73+
74+
//tabs
75+
$statement->execute(['TABS']);
76+
$count['tabs'] = $statement->fetch()[0];
77+
78+
//spaces
79+
$statement->execute(['SPACES']);
80+
$count['spaces'] = $statement->fetch()[0];
81+
82+
return $count;
83+
}
84+
85+
public function save($team)
86+
{
87+
$sql = "INSERT INTO votes (time_cast, candidate) VALUES (GETDATE(), :candidate)";
88+
$statement = $this->connection->prepare($sql);
89+
$statement->bindParam('candidate', $team);
90+
91+
if ($statement->execute()) {
92+
return "Vote successfully cast for '$team'";
93+
}
94+
95+
return print_r($statement->errorInfo(), true);
96+
}
97+
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
<!--
2+
Copyright 2020 Google LLC
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
-->
16+
<html lang="en">
17+
<head>
18+
<title>Tabs VS Spaces</title>
19+
<link rel="stylesheet"
20+
href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">
21+
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
22+
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
23+
</head>
24+
<body>
25+
<nav class="red lighten-1">
26+
<div class="nav-wrapper">
27+
<a href="#" class="brand-logo center">Tabs VS Spaces</a>
28+
</div>
29+
</nav>
30+
<div class="section">
31+
<div class="center">
32+
<h4>
33+
<?php if ($tab_count == $space_count): ?>
34+
TABS and SPACES are evenly matched!
35+
<?php elseif ($tab_count > $space_count): ?>
36+
TABS are winning by <?=$tab_count - $space_count?>
37+
<?= $tab_count - $space_count > 1 ? "votes" : "vote" ?>!
38+
<?php elseif ($space_count > $tab_count): ?>
39+
SPACES are winning by <?=$space_count - $tab_count?>
40+
<?= $space_count - $tab_count > 1 ? "votes" : "vote" ?>!
41+
<?php endif ?>
42+
</h4>
43+
</div>
44+
<div class="row center">
45+
<div class="col s6 m5 offset-m1">
46+
<div class="card-panel <?= $tab_count > $space_count ?: 'green lighten-3' ?>">
47+
<i class="material-icons large">keyboard_tab</i>
48+
<h3><?=$tab_count?> votes</h3>
49+
<button id="voteTabs" class="btn green">Vote for TABS</button>
50+
</div>
51+
</div>
52+
<div class="col s6 m5">
53+
<div class="card-panel <?= $tab_count < $space_count ?: 'blue lighten-3' ?>">
54+
<i class="material-icons large">space_bar</i>
55+
<h3><?=$space_count?> votes</h3>
56+
<button id="voteSpaces" class="btn blue">Vote for SPACES</button>
57+
</div>
58+
</div>
59+
</div>
60+
<h4 class="header center">Recent Votes</h4>
61+
<ul class="container collection center">
62+
<?php foreach ($list as $vote): ?>
63+
<li class="collection-item avatar">
64+
<?php if ($vote['candidate'] == "TABS"): ?>
65+
<i class="material-icons circle green">keyboard_tab</i>
66+
<?php elseif ($vote['candidate'] == "SPACES"): ?>
67+
<i class="material-icons circle blue">space_bar</i>
68+
<?php endif ?>
69+
<span class="title">
70+
A vote for <b><?= $vote['candidate'] ?></b>
71+
</span>
72+
<p>was cast at <?= $vote['time_cast'] ?></p>
73+
</li>
74+
<?php endforeach ?>
75+
</ul>
76+
</div>
77+
<script>
78+
function vote(team) {
79+
var xhr = new XMLHttpRequest();
80+
xhr.onreadystatechange = function () {
81+
if (this.readyState == 4) {
82+
if (!window.alert(this.responseText)) {
83+
window.location.reload();
84+
}
85+
}
86+
};
87+
xhr.open("POST", "/", true);
88+
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
89+
xhr.send("team=" + team);
90+
}
91+
document.getElementById("voteTabs").addEventListener("click", function () {
92+
vote("TABS");
93+
});
94+
document.getElementById("voteSpaces").addEventListener("click", function () {
95+
vote("SPACES");
96+
});
97+
</script>
98+
</body>
99+
</html>

0 commit comments

Comments
 (0)