Skip to content

Commit 74f4964

Browse files
committed
refactor to slim app
1 parent 47c048d commit 74f4964

File tree

10 files changed

+462
-141
lines changed

10 files changed

+462
-141
lines changed

cloud_sql/sqlserver/pdo/README.md

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,36 +3,49 @@
33
## Before you begin
44

55
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/).
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/). Once you've installed composer, use it to install required dependencies by running `composer install`.
77
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.
88
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.
99
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:
10+
11+
## Running Locally
12+
13+
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).
14+
15+
To authenticate with Cloud SQL, set the `$GOOGLE_APPLICATION_CREDENTIALS` environment variable:
1116

1217
```bash
1318
export GOOGLE_APPLICATION_CREDENTIALS=/path/to/service/account/key.json
14-
export CLOUD_SQL_CONNECTION_NAME='::'
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='(local)'
1919
```
2020

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.
21+
To run the Cloud SQL proxy, you need to set the instance connection name. See the instructions [here](https://cloud.google.com/sql/docs/sqlserver/quickstart-proxy-test#get_the_instance_connection_name) for finding the instance connection name.
2222

23-
## Running Locally
23+
```bash
24+
export CLOUD_SQL_CONNECTION_NAME='::'
25+
```
2426

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).
27+
Once the proxy is ready, use one of the following commands to start the proxy in the background.
2628

27-
Once the proxy is ready, use the following command to start the proxy in the background:
29+
You may connect to your instance via TCP. To connect via TCP, you must provide a port as part of the instance name, as demonstrated below.
2830

2931
```bash
30-
$ ./cloud_sql_proxy -dir=/cloudsql \
32+
$ ./cloud_sql_proxy \
3133
--instances=$CLOUD_SQL_CONNECTION_NAME=tcp:1433 \
3234
--credential_file=$GOOGLE_APPLICATION_CREDENTIALS
3335
```
3436

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.
37+
### Set Configuration Values
38+
39+
Set the required environment variables for your connection to Cloud SQL.
40+
41+
```bash
42+
export DB_USER='my-db-user'
43+
export DB_PASS='my-db-pass'
44+
export DB_NAME='my-db-name'
45+
export DB_HOSTNAME='127.0.0.1'
46+
```
47+
48+
Note: Saving credentials in environment variables is convenient, but not secure - consider a more secure solution such as [Secret Manager](https://cloud.google.com/secret-manager/) to help keep secrets safe.
3649

3750
Execute the following:
3851

cloud_sql/sqlserver/pdo/app.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,13 @@
1515
runtime: php72
1616

1717
# Remember - storing secrets in plaintext is potentially unsafe. Consider using
18-
# something like https://cloud.google.com/kms/ to help keep secrets secret.
18+
# something like https://cloud.google.com/secret-manager/ to help keep secrets
19+
# secret.
1920
env_variables:
20-
CLOUD_SQL_CONNECTION_NAME: ::
2121
DB_USER: my-db-user
2222
DB_PASS: my-db-pass
23-
DB_NAME: my_db
24-
DB_HOSTNAME: localhost
23+
DB_NAME: my-db
24+
DB_HOSTNAME: "172.17.0.1"
2525

2626
# Defaults to "serve index.php" and "serve public/index.php". Can be used to
2727
# serve a custom PHP front controller (e.g. "serve backend/index.php") or to

cloud_sql/sqlserver/pdo/composer.json

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"name": "google/cloud-sql-sqlserver-example",
3+
"autoload": {
4+
"psr-4": {
5+
"Google\\Cloud\\Samples\\CloudSQL\\SQLServer\\": "src"
6+
}
7+
},
8+
"autoload-dev": {
9+
"psr-4": {
10+
"Google\\Cloud\\Samples\\CloudSQL\\SQLServer\\Tests\\": "src"
11+
}
12+
},
13+
"require": {
14+
"php": ">= 7.2",
15+
"slim/slim": "^4.5",
16+
"slim/twig-view": "^3.1",
17+
"pimple/pimple": "^3.3",
18+
"guzzlehttp/psr7": "^1.6",
19+
"http-interop/http-factory-guzzle": "^1.0"
20+
},
21+
"require-dev": {
22+
"phpunit/phpunit": "^8.5"
23+
}
24+
}

cloud_sql/sqlserver/pdo/index.php

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,28 +15,40 @@
1515
* limitations under the License.
1616
*/
1717

18-
require_once 'src/DB.php';
19-
require_once 'src/Votes.php';
18+
declare(strict_types=1);
2019

21-
use Google\Cloud\Samples\CloudSQL\SQLServer\DB;
22-
use Google\Cloud\Samples\CloudSQL\SQLServer\Votes;
20+
use GuzzleHttp\Psr7;
2321

24-
$votes = new Votes(DB::createPdoConnection());
22+
include __DIR__ . '/vendor/autoload.php';
2523

26-
if ($_SERVER['REQUEST_URI'] == '/' && $_SERVER['REQUEST_METHOD'] == 'GET') {
27-
$list = $votes->list();
24+
$app = include __DIR__ . '/src/app.php';
2825

29-
$vote_count = $votes->count_candidates();
30-
$tab_count = $vote_count['tabs'];
31-
$space_count = $vote_count['spaces'];
26+
$app->get('/', function ($request, $response) {
27+
$this->get('votes')->createTableIfNotExists();
28+
29+
return $this->get('view')->render($response, 'template.twig', [
30+
'votes' => $this->get('votes')->listVotes(),
31+
'tabCount' => $this->get('votes')->getCountByValue('TABS'),
32+
'spaceCount' => $this->get('votes')->getCountByValue('SPACES'),
33+
]);
34+
});
35+
36+
$app->post('/', function ($request, $response) {
37+
$this->get('votes')->createTableIfNotExists();
3238

33-
include_once("./template.php");
34-
} elseif ($_SERVER['REQUEST_URI'] == '/' && $_SERVER['REQUEST_METHOD'] == 'POST') {
3539
$message = 'Invalid vote. Choose Between TABS and SPACES';
3640

37-
if (!empty($_POST['team']) && in_array($_POST['team'], ['SPACES', 'TABS'])) {
38-
$message = $votes->save($_POST['team']);
41+
$formData = $request->getParsedBody() + [
42+
'voteValue' => ''
43+
];
44+
45+
if (in_array($formData['voteValue'], ['SPACES', 'TABS'])) {
46+
$message = $this->get('votes')->insertVote($formData['voteValue'])
47+
? 'Vote cast for ' . $formData['voteValue']
48+
: 'An error occurred';
3949
}
4050

41-
echo $message;
42-
}
51+
return $response->withBody(Psr7\stream_for($message));
52+
});
53+
54+
$app->run();
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
2+
3+
4+
5+
tests
6+
7+
8+
9+
10+
src
11+
12+
13+

cloud_sql/sqlserver/pdo/src/DB.php

Lines changed: 0 additions & 42 deletions
This file was deleted.

cloud_sql/sqlserver/pdo/src/Votes.php

Lines changed: 72 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -15,83 +15,119 @@
1515
* limitations under the License.
1616
*/
1717

18+
declare(strict_types=1);
19+
1820
namespace Google\Cloud\Samples\CloudSQL\SQLServer;
1921

2022
use PDO;
23+
use PDOException;
24+
use RuntimeException;
2125

26+
/**
27+
* Manage votes using the Cloud SQL database.
28+
*/
2229
class Votes
2330
{
31+
/**
32+
* @var PDO
33+
*/
2434
private $connection;
2535

36+
/**
37+
* @param PDO $connection A connection to the database.
38+
*/
2639
public function __construct(PDO $connection)
2740
{
2841
$this->connection = $connection;
29-
$this->create_table();
3042
}
3143

32-
private function create_table()
44+
/**
45+
* Creates the table if it does not yet exist.
46+
*
47+
* @return void
48+
*/
49+
public function createTableIfNotExists()
3350
{
34-
$tableName = "votes";
35-
3651
$existsStmt = "SELECT * FROM INFORMATION_SCHEMA.TABLES
3752
WHERE TABLE_NAME = ?";
3853

3954
$stmt = $this->connection->prepare($existsStmt);
40-
$stmt->execute([$tableName]);
55+
$stmt->execute(['votes']);
4156

42-
// If table does not exist, create it!
4357
$row = $stmt->fetch(PDO::FETCH_ASSOC);
58+
59+
// If the table does not exist, create it.
4460
if (!$row) {
45-
$sql = "
46-
CREATE TABLE votes (
61+
$sql = "CREATE TABLE votes (
4762
vote_id INT NOT NULL IDENTITY,
4863
time_cast DATETIME NOT NULL,
49-
candidate VARCHAR(6) NOT NULL,
64+
vote_value VARCHAR(6) NOT NULL,
5065
PRIMARY KEY (vote_id)
5166
);";
52-
if ($this->connection->exec($sql) !== 1) {
53-
print_r($this->connection->errorInfo());
54-
exit;
55-
}
67+
68+
$this->connection->exec($sql);
5669
}
5770
}
5871

59-
public function list()
72+
/**
73+
* Returns a list of the last five votes
74+
*
75+
* @return array
76+
*/
77+
public function listVotes() : array
6078
{
61-
$sql = "SELECT TOP 5 candidate, time_cast FROM votes ORDER BY time_cast DESC";
79+
$sql = "SELECT TOP 5 vote_value, time_cast FROM votes ORDER BY time_cast DESC";
6280
$statement = $this->connection->prepare($sql);
6381
$statement->execute();
64-
return $statement->fetchAll();
82+
return $statement->fetchAll(PDO::FETCH_ASSOC);
6583
}
6684

67-
public function count_candidates()
85+
/**
86+
* Get the number of votes cast for a given value.
87+
*
88+
* @param string $value
89+
* @param int
90+
*/
91+
public function getCountByValue(string $value) : int
6892
{
69-
$sql = "SELECT COUNT(vote_id) as voteCount FROM votes WHERE candidate = ?";
70-
$count = [];
93+
$sql = "SELECT COUNT(vote_id) as voteCount FROM votes WHERE vote_value = ?";
7194

7295
$statement = $this->connection->prepare($sql);
96+
$statement->execute([$value]);
7397

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;
98+
return (int) $statement->fetch(PDO::FETCH_COLUMN);
8399
}
84100

85-
public function save($team)
101+
/**
102+
* Insert a new vote into the database
103+
*
104+
* @param string $value The value to vote for.
105+
* @return boolean
106+
*/
107+
public function insertVote(string $value) : bool
86108
{
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'";
109+
$conn = $this->connection;
110+
$res = false;
111+
112+
# [START cloud_sql_sqlserver_pdo_connection]
113+
// Use prepared statements to guard against SQL injection.
114+
$sql = "INSERT INTO votes (time_cast, vote_value) VALUES (GETDATE(), :voteValue)";
115+
116+
try {
117+
$statement = $conn->prepare($sql);
118+
$statement->bindParam('voteValue', $value);
119+
120+
$res = $statement->execute();
121+
} catch (PDOException $e) {
122+
throw new RuntimeException(
123+
"Could not insert vote into database. The PDO exception was " .
124+
$e->getMessage(),
125+
$e->getCode(),
126+
$e
127+
);
93128
}
129+
# [END cloud_sql_sqlserver_pdo_connection]
94130

95-
return print_r($statement->errorInfo(), true);
131+
return $res;
96132
}
97133
}

0 commit comments

Comments
 (0)