Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
2018-10-31 DB: added MongoDB 4 examples using the latest PHP MongoDB …
…driver
- Loading branch information
dbierer
committed
Oct 31, 2018
1 parent
817ff40
commit 8d52b97
Showing
146 changed files
with
2,296 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
# MongoDB 3 Examples | ||
|
||
* The examples in this repo are mainly based on work which I did in 2013. It's based on MongoDB 3.4 and uses the old (and now deprecated) `Mongo` PHP Database driver. | ||
* For more information about this driver see: http://php.net/manual/en/book.mongo.php. | ||
* If you are starting a new project, it is recommended that you use MongoDB 4 or above, and the currently maintained `MongoDB` driver | ||
* For more information about the new driver see: http://php.net/manual/en/set.mongodb.php | ||
* Look for a directory `mongoDB_4` for examples using this driver |
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
vendor/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
<?php | ||
namespace Application; | ||
|
||
use Throwable; | ||
use MongoDB\Model\BSONDocument; | ||
|
||
/** | ||
* Used by add.php to add a new purchase to the database | ||
*/ | ||
class Add extends Base | ||
{ | ||
|
||
/** | ||
* Returns customer document | ||
* | ||
* @return MongoDB\Model\BSONDocument $customer | ||
*/ | ||
public function findCustomerByName($name) | ||
{ | ||
|
||
// build projection: these are the fields we will include in the purchase | ||
$options = [ | ||
'projection' => [ | ||
'_id' => 1, | ||
'name' => 1, | ||
'state_province' => 1, | ||
'country' => 1, | ||
'balance' => 1, | ||
'purch_history' => 1 | ||
] | ||
]; | ||
// perform find | ||
$result = NULL; | ||
try { | ||
$result = $this->customers->findOne(['name' => $name], $options); | ||
} catch (Throwable $e) { | ||
error_log(__METHOD__ . ':' . $e->getMessage()); | ||
} | ||
return $result; | ||
} | ||
/** | ||
* Returns product document | ||
* | ||
* @return MongoDB\Model\BSONDocument $product | ||
*/ | ||
public function findProductBySku($sku) | ||
{ | ||
|
||
// build projection: in the purchase we suppress the description | ||
$options = ['projection' => ['description' => 0]]; | ||
// perform find | ||
$result = NULL; | ||
try { | ||
$result = $this->products->findOne(['sku' => $sku], $options); | ||
} catch (Throwable $e) { | ||
error_log(__METHOD__ . ':' . $e->getMessage()); | ||
} | ||
return $result; | ||
} | ||
/** | ||
* Insert new purchase without transaction support | ||
* | ||
* @param MongoDB\Model\BSONDocument $customer | ||
* @param MongoDB\Model\BSONDocument $product | ||
* @param int $quantity | ||
* @return boolean $result | ||
*/ | ||
public function savePurchase(BSONDocument $customer, BSONDocument $product, $quantity) | ||
{ | ||
$result = FALSE; | ||
$date = date(self::DATE_FORMAT); | ||
$session = $this->connection->getSession(); | ||
$data = [ | ||
'customer' => $customer, | ||
'product' => $product, | ||
'date' => $date, | ||
'quantity' => $quantity, | ||
'amount' => $quantity * (float) $product->price | ||
]; | ||
try { | ||
if ($result = $this->purchases->insertOne($data)) { | ||
// add date to customer purchase history | ||
$list = $customer->purch_history; | ||
$list[] = $date; | ||
$this->customers->updateOne( | ||
['name' => $customer->name], | ||
['$set' => ['purch_history' => $list]]); | ||
} | ||
} catch (Throwable $e) { | ||
$result = FALSE; | ||
error_log(__METHOD__ . ':' . $e->getMessage()); | ||
} | ||
return $result; | ||
} | ||
/** | ||
* Insert new purchase with transaction support(only available in MongoDB v4.0+) | ||
* See: https://docs.mongodb.com/manual/core/transactions/#transactions | ||
* Can only run on a replica set!!! | ||
* | ||
* @param MongoDB\Model\BSONDocument $customer | ||
* @param MongoDB\Model\BSONDocument $product | ||
* @param int $quantity | ||
* @return boolean $result | ||
*/ | ||
public function savePurchaseWithSession(BSONDocument $customer, BSONDocument $product, $quantity) | ||
{ | ||
// init vars | ||
$result = FALSE; | ||
$date = date(self::DATE_FORMAT); | ||
|
||
// get MongoDB\Driver\Session which is used for transaction support | ||
$session = $this->connection->getSession(); | ||
$data = [ | ||
'customer' => $customer, | ||
'product' => $product, | ||
'date' => $date, | ||
'quantity' => $quantity, | ||
'amount' => $quantity * (float) $product->price | ||
]; | ||
try { | ||
// begin transaction | ||
$session->startTransaction(); | ||
// need to add session as an option to get transaction support | ||
if ($result = $this->purchases->insertOne($data, ['session' => $session])) { | ||
$list = $customer->purch_history; | ||
$list[] = $date; | ||
$this->customers->updateOne( | ||
['name' => $customer->name], | ||
['$set' => ['purch_history' => $list]], | ||
// need to add session as an option to get transaction support | ||
['session' => $session]); | ||
} | ||
// commit | ||
$session->commitTransaction(); | ||
} catch (Throwable $e) { | ||
// rollback | ||
$session->abortTransaction(); | ||
$result = FALSE; | ||
error_log(__METHOD__ . ':' . $e->getMessage()); | ||
} | ||
return $result; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
<?php | ||
namespace Application; | ||
|
||
/** | ||
* Serves as base class for Main, Lookup and Add | ||
*/ | ||
class Base | ||
{ | ||
|
||
const DATE_FORMAT = 'Y-m-d'; | ||
const DEFAULT_URL = '/json.php'; | ||
const DEFAULT_LIMIT = 100; | ||
const DEFAULT_END_DATE = 'P99Y'; | ||
|
||
protected $connection; | ||
protected $products; | ||
protected $purchases; | ||
protected $customers; | ||
|
||
public function __construct($config) | ||
{ | ||
$this->connection = new Connection($config); | ||
$client = $this->connection->getClient(); | ||
$this->products = $client->sweetscomplete->products; | ||
$this->purchases = $client->sweetscomplete->purchases; | ||
$this->customers = $client->sweetscomplete->customers; | ||
} | ||
/** | ||
* Gives access to Application\Connection | ||
* which in turn gives access to the client, manager and session | ||
* | ||
* @return Application\Connection $connection | ||
*/ | ||
public function getConnection() | ||
{ | ||
return $this->connection; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
<?php | ||
namespace Application; | ||
|
||
use Exception; | ||
use MongoDB\Client as MongoClient; | ||
/** | ||
* Creates instance of MongoDB\Client | ||
* Only accepts 1 host | ||
*/ | ||
class Client | ||
{ | ||
|
||
const ERROR_HOST = 'ERROR: host must be specified'; | ||
const ERROR_OPTS = 'ERROR: options must be an array even if only one'; | ||
protected $uri; | ||
protected $mongoClient; | ||
public function __construct($config) | ||
{ | ||
$this->uri = $this->buildUri($config); | ||
$this->mongoClient = new MongoClient($this->uri); | ||
} | ||
public function getClient() | ||
{ | ||
return $this->mongoClient; | ||
} | ||
// see: https://docs.mongodb.com/manual/reference/connection-string/#standard-connection-string-format | ||
public function buildUri($config) | ||
{ | ||
$uri = 'mongodb://'; | ||
if (isset($config['username']) && isset($config['password'])) { | ||
$uri .= $config['username'] . ':' . $config['password'] . '@'; | ||
} | ||
if (!isset($config['host'])) { | ||
throw new Exception(self::ERROR_HOST); | ||
} | ||
$uri .= $config['host']; | ||
$uri .= (isset($config['port'])) ? ':' . $config['port'] : ''; | ||
$uri .= (isset($config['database'])) ? '/' . $config['database'] : ''; | ||
if (isset($config['options'])) { | ||
if (!is_array($config['options'])) { | ||
throw new Exception(self::ERROR_OPTS); | ||
} | ||
$uri .= '?'; | ||
foreach ($config['options'] as $key => $value) { | ||
$uri .= $key . '=' . $value . '&'; | ||
} | ||
// trim trailing '&' | ||
$uri = substr($uri, 0, -1); | ||
} | ||
return $uri; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
<?php | ||
namespace Application; | ||
|
||
use Exception; | ||
use MongoDB\Client as MongoClient; | ||
/** | ||
* Creates instance of MongoDB\Client | ||
* Only accepts 1 host | ||
*/ | ||
class Connection | ||
{ | ||
|
||
const ERROR_HOST = 'ERROR: host must be specified'; | ||
const ERROR_OPTS = 'ERROR: options must be an array even if only one'; | ||
const ERROR_CONFIG_URI = 'ERROR: must include a key "uri" in config with MongoDB connection info'; | ||
|
||
protected $mongoClient; | ||
protected $manager; // MongoDB\Driver\Manager | ||
public function __construct($config) | ||
{ | ||
if (!isset($config['uri'])) { | ||
throw new Exception(self::ERROR_CONFIG_URI); | ||
} | ||
$uriOpts = $config['uriOpts'] ?? []; | ||
$driverOpts = $config['driverOpts'] ?? []; | ||
$uri = $this->buildUri($config); | ||
$this->mongoClient = new MongoClient($uri, $uriOpts, $driverOpts); | ||
$this->manager = $this->mongoClient->getManager(); | ||
} | ||
public function getClient() | ||
{ | ||
return $this->mongoClient; | ||
} | ||
public function getManager() | ||
{ | ||
return $this->manager; | ||
} | ||
public function getSession() | ||
{ | ||
return $this->manager->startSession(); | ||
} | ||
// see: https://docs.mongodb.com/manual/reference/connection-string/#standard-connection-string-format | ||
public function buildUri($config) | ||
{ | ||
$uri = 'mongodb://'; | ||
if (isset($config['uri']['username']) && isset($config['uri']['password'])) | ||
$uri .= $config['uri']['username'] . ':' . $config['uri']['password'] . '@'; | ||
if (!isset($config['uri']['host'])) | ||
throw new Exception(self::ERROR_HOST); | ||
$uri .= $config['uri']['host']; | ||
$uri .= (isset($config['uri']['port'])) ? ':' . $config['uri']['port'] : ''; | ||
$uri .= (isset($config['uri']['database'])) ? '/' . $config['uri']['database'] : ''; | ||
if (isset($config['uriOpts'])) { | ||
if (!is_array($config['uriOpts'])) | ||
throw new Exception(self::ERROR_OPTS); | ||
$uri .= '?'; | ||
foreach ($config['uriOpts'] as $key => $value) | ||
$uri .= $key . '=' . $value . '&'; | ||
// trim trailing '&' | ||
$uri = substr($uri, 0, -1); | ||
} | ||
return $uri; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
<?php | ||
namespace Application; | ||
|
||
use Exception; | ||
use SplFileObject; | ||
class Csv | ||
{ | ||
const ERROR_FILE = 'ERROR: file does not exist'; | ||
protected $csvFile; | ||
protected $headers; | ||
public function __construct($fn) | ||
{ | ||
if (!file_exists($fn)) throw new Exception(self::ERROR_FILE); | ||
$this->csvFile = new SplFileObject($fn, 'r'); | ||
} | ||
public function getHeaders() | ||
{ | ||
if (!$this->headers) { | ||
$this->csvFile->rewind(); | ||
$this->headers = $this->csvFile->fgetcsv(); | ||
} | ||
return $this->headers; | ||
} | ||
public function getIterator() | ||
{ | ||
$this->csvFile->rewind(); | ||
while ($line = $this->csvFile->fgetcsv()) { | ||
if (is_array($line)) yield $line; | ||
} | ||
} | ||
public function getIteratorWithHeaders() | ||
{ | ||
foreach ($this->getIterator() as $line) { | ||
if (count($this->getHeaders()) == count($line)) { | ||
yield array_combine($this->getHeaders(), $line); | ||
} | ||
} | ||
} | ||
} | ||
|
Oops, something went wrong.