Commit 2e5caa15 by hcy001

1

parent 17d4adeb
Showing with 5366 additions and 3 deletions
......@@ -25,6 +25,12 @@ class HdController extends Controller
//添加参数
private function cf(){
$mongo = \DB::connection("mongodbs")
->collection("spu")
// ->where("****","***")
->first();
print_r($mongo);
die();
$param = [
["spu_name"=>"RCP0603W110RGS3","brand_name"=>"vishay"]
];
......
......@@ -13,7 +13,8 @@
"vladimir-yuldashev/laravel-queue-rabbitmq": "5.2",
"artisaninweb/laravel-soap": "0.2.*",
"hprose/hprose": "^2.0",
"barryvdh/laravel-dompdf": "^0.8.2"
"barryvdh/laravel-dompdf": "^0.8.2",
"jenssegers/mongodb": "2.3"
},
"require-dev": {
......
......@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "758b5dc4d97e06149cb8a2a50dcf0487",
"content-hash": "98f95b32ed02c6f50300f4c0347aff51",
"packages": [
{
"name": "artisaninweb/laravel-soap",
......@@ -672,6 +672,64 @@
"time": "2015-04-20T18:58:01+00:00"
},
{
"name": "jenssegers/mongodb",
"version": "v2.3.0",
"source": {
"type": "git",
"url": "https://github.com/jenssegers/laravel-mongodb.git",
"reference": "22063084ea4370c3865b2364f56d0508f09ec4e8"
},
"dist": {
"type": "zip",
"url": "https://repo.huaweicloud.com/repository/php/dist/jenssegers/mongodb/jenssegers-mongodb-v2.3.0-22063084.zip",
"reference": "22063084ea4370c3865b2364f56d0508f09ec4e8",
"shasum": "2d4d44926acd4fe21db31e529f64b537c59242c7"
},
"require": {
"illuminate/container": "^5.1",
"illuminate/database": "^5.1",
"illuminate/events": "^5.1",
"illuminate/support": "^5.1"
},
"require-dev": {
"mockery/mockery": "^0.9",
"orchestra/testbench": "^3.1",
"phpunit/phpunit": "^4.0|^5.0",
"satooshi/php-coveralls": "^0.6"
},
"suggest": {
"jenssegers/mongodb-sentry": "Add Sentry support to Laravel-MongoDB",
"jenssegers/mongodb-session": "Add MongoDB session support to Laravel-MongoDB"
},
"type": "library",
"autoload": {
"psr-0": {
"Jenssegers\\Mongodb": "src/",
"Jenssegers\\Eloquent": "src/"
}
},
"license": [
"MIT"
],
"authors": [
{
"name": "Jens Segers",
"homepage": "https://jenssegers.com"
}
],
"description": "A MongoDB based Eloquent model and Query builder for Laravel 4",
"homepage": "https://github.com/jenssegers/laravel-mongodb",
"keywords": [
"database",
"eloquent",
"laravel",
"model",
"mongo",
"mongodb"
],
"time": "2016-02-03T23:25:16+00:00"
},
{
"name": "jeremeamia/SuperClosure",
"version": "2.4.0",
"source": {
......@@ -2876,6 +2934,7 @@
"faker",
"fixtures"
],
"abandoned": true,
"time": "2017-08-15T16:48:10+00:00"
},
{
......
......@@ -162,6 +162,7 @@ return [
Artisaninweb\SoapWrapper\ServiceProvider::class,
Barryvdh\DomPDF\ServiceProvider::class,
Jenssegers\Mongodb\MongodbServiceProvider::class,
],
......@@ -211,6 +212,7 @@ return [
'Excel' => Maatwebsite\Excel\Facades\Excel::class,
'SoapWrapper' => Artisaninweb\SoapWrapper\Facades\SoapWrapper::class,
'PDF' => Barryvdh\DomPDF\Facade::class
],
];
......@@ -122,6 +122,17 @@ return [
'password' => env('RABBITMQ_PASSWORD', 'guest'),
'queue' => env('RABBITMQ_QUEUE'), // name of the default queue,
],
'mongodbs' => [
'driver' => 'mongodb',
'host' => env('DB_MONGO_HOST', ''),
'database' => env('DB_MONGO_DATABASE', ''),
'username' => env('DB_MONGO_USERNAME', ''),
'password' => env('DB_MONGO_PASSWORD', ''),
'port' => env('DB_MONGO_PORT', 27017),
// 'options' => [
// 'database' => 'ichunt' // sets the authentication database required by mongo 3
// ]
],
],
/*
......
<?php
ini_set('mongo.long_as_object', 1);
/**
* Laravel - A PHP Framework For Web Artisans
*
......
......@@ -23,18 +23,23 @@ return array(
'App\\Http\\Controllers\\WebController' => $baseDir . '/app/Http/Controllers/WebController.php',
'App\\Http\\Kernel' => $baseDir . '/app/Http/Kernel.php',
'App\\Http\\Middleware\\CheckLogin' => $baseDir . '/app/Http/Middleware/CheckLogin.php',
'App\\Http\\Middleware\\EnableCrossRequestMiddleware' => $baseDir . '/app/Http/Middleware/EnableCrossRequestMiddleware.php',
'App\\Http\\Middleware\\JsonpCallback' => $baseDir . '/app/Http/Middleware/JsonpCallback.php',
'App\\Http\\Middleware\\WmsVerification' => $baseDir . '/app/Http/Middleware/WmsVerification.php',
'App\\Http\\Requests\\Request' => $baseDir . '/app/Http/Requests/Request.php',
'App\\Jobs\\Job' => $baseDir . '/app/Jobs/Job.php',
'App\\Model\\CmsModel' => $baseDir . '/app/Model/CmsModel.php',
'App\\Model\\CommonModel' => $baseDir . '/app/Model/CommonModel.php',
'App\\Model\\InquiryItemsAssignModel' => $baseDir . '/app/Model/InquiryItemsAssignModel.php',
'App\\Model\\InquiryItemsModel' => $baseDir . '/app/Model/InquiryItemsModel.php',
'App\\Model\\InquiryItemsReportModel' => $baseDir . '/app/Model/InquiryItemsReportModel.php',
'App\\Model\\InquiryItemsUrgeModel' => $baseDir . '/app/Model/InquiryItemsUrgeModel.php',
'App\\Model\\InquiryModel' => $baseDir . '/app/Model/InquiryModel.php',
'App\\Model\\InquiryUsersModel' => $baseDir . '/app/Model/InquiryUsersModel.php',
'App\\Model\\LoginModel' => $baseDir . '/app/Model/LoginModel.php',
'App\\Model\\OpLogModel' => $baseDir . '/app/Model/OpLogModel.php',
'App\\Model\\QuoteModel' => $baseDir . '/app/Model/QuoteModel.php',
'App\\Model\\SearchModel' => $baseDir . '/app/Model/SearchModel.php',
'App\\Model\\Server\\ExportModel' => $baseDir . '/app/Model/ExportModel.php',
'App\\Model\\Server\\GoModel' => $baseDir . '/app/Model/GoModel.php',
'App\\Model\\SupplierChannelComModel' => $baseDir . '/app/Model/SupplierChannelComModel.php',
......@@ -1387,6 +1392,29 @@ return array(
'JakubOnderka\\PhpConsoleColor\\ConsoleColor' => $vendorDir . '/jakub-onderka/php-console-color/src/JakubOnderka/PhpConsoleColor/ConsoleColor.php',
'JakubOnderka\\PhpConsoleColor\\InvalidStyleException' => $vendorDir . '/jakub-onderka/php-console-color/src/JakubOnderka/PhpConsoleColor/InvalidStyleException.php',
'JakubOnderka\\PhpConsoleHighlighter\\Highlighter' => $vendorDir . '/jakub-onderka/php-console-highlighter/src/JakubOnderka/PhpConsoleHighlighter/Highlighter.php',
'Jenssegers\\Eloquent\\Model' => $vendorDir . '/jenssegers/mongodb/src/Jenssegers/Eloquent/Model.php',
'Jenssegers\\Mongodb\\Auth\\DatabaseTokenRepository' => $vendorDir . '/jenssegers/mongodb/src/Jenssegers/Mongodb/Auth/DatabaseTokenRepository.php',
'Jenssegers\\Mongodb\\Auth\\PasswordResetServiceProvider' => $vendorDir . '/jenssegers/mongodb/src/Jenssegers/Mongodb/Auth/PasswordResetServiceProvider.php',
'Jenssegers\\Mongodb\\Collection' => $vendorDir . '/jenssegers/mongodb/src/Jenssegers/Mongodb/Collection.php',
'Jenssegers\\Mongodb\\Connection' => $vendorDir . '/jenssegers/mongodb/src/Jenssegers/Mongodb/Connection.php',
'Jenssegers\\Mongodb\\Eloquent\\Builder' => $vendorDir . '/jenssegers/mongodb/src/Jenssegers/Mongodb/Eloquent/Builder.php',
'Jenssegers\\Mongodb\\Eloquent\\HybridRelations' => $vendorDir . '/jenssegers/mongodb/src/Jenssegers/Mongodb/Eloquent/HybridRelations.php',
'Jenssegers\\Mongodb\\Eloquent\\SoftDeletes' => $vendorDir . '/jenssegers/mongodb/src/Jenssegers/Mongodb/Eloquent/SoftDeletes.php',
'Jenssegers\\Mongodb\\Model' => $vendorDir . '/jenssegers/mongodb/src/Jenssegers/Mongodb/Model.php',
'Jenssegers\\Mongodb\\MongodbServiceProvider' => $vendorDir . '/jenssegers/mongodb/src/Jenssegers/Mongodb/MongodbServiceProvider.php',
'Jenssegers\\Mongodb\\Query\\Builder' => $vendorDir . '/jenssegers/mongodb/src/Jenssegers/Mongodb/Query/Builder.php',
'Jenssegers\\Mongodb\\Query\\Grammar' => $vendorDir . '/jenssegers/mongodb/src/Jenssegers/Mongodb/Query/Grammar.php',
'Jenssegers\\Mongodb\\Query\\Processor' => $vendorDir . '/jenssegers/mongodb/src/Jenssegers/Mongodb/Query/Processor.php',
'Jenssegers\\Mongodb\\Relations\\BelongsTo' => $vendorDir . '/jenssegers/mongodb/src/Jenssegers/Mongodb/Relations/BelongsTo.php',
'Jenssegers\\Mongodb\\Relations\\BelongsToMany' => $vendorDir . '/jenssegers/mongodb/src/Jenssegers/Mongodb/Relations/BelongsToMany.php',
'Jenssegers\\Mongodb\\Relations\\EmbedsMany' => $vendorDir . '/jenssegers/mongodb/src/Jenssegers/Mongodb/Relations/EmbedsMany.php',
'Jenssegers\\Mongodb\\Relations\\EmbedsOne' => $vendorDir . '/jenssegers/mongodb/src/Jenssegers/Mongodb/Relations/EmbedsOne.php',
'Jenssegers\\Mongodb\\Relations\\EmbedsOneOrMany' => $vendorDir . '/jenssegers/mongodb/src/Jenssegers/Mongodb/Relations/EmbedsOneOrMany.php',
'Jenssegers\\Mongodb\\Relations\\HasMany' => $vendorDir . '/jenssegers/mongodb/src/Jenssegers/Mongodb/Relations/HasMany.php',
'Jenssegers\\Mongodb\\Relations\\HasOne' => $vendorDir . '/jenssegers/mongodb/src/Jenssegers/Mongodb/Relations/HasOne.php',
'Jenssegers\\Mongodb\\Relations\\MorphTo' => $vendorDir . '/jenssegers/mongodb/src/Jenssegers/Mongodb/Relations/MorphTo.php',
'Jenssegers\\Mongodb\\Schema\\Blueprint' => $vendorDir . '/jenssegers/mongodb/src/Jenssegers/Mongodb/Schema/Blueprint.php',
'Jenssegers\\Mongodb\\Schema\\Builder' => $vendorDir . '/jenssegers/mongodb/src/Jenssegers/Mongodb/Schema/Builder.php',
'JsonSerializable' => $vendorDir . '/nesbot/carbon/src/JsonSerializable.php',
'League\\Flysystem\\AdapterInterface' => $vendorDir . '/league/flysystem/src/AdapterInterface.php',
'League\\Flysystem\\Adapter\\AbstractAdapter' => $vendorDir . '/league/flysystem/src/Adapter/AbstractAdapter.php',
......
......@@ -12,6 +12,8 @@ return array(
'PHPExcel' => array($vendorDir . '/phpoffice/phpexcel/Classes'),
'Mockery' => array($vendorDir . '/mockery/mockery/library'),
'Maatwebsite\\Excel\\' => array($vendorDir . '/maatwebsite/excel/src'),
'Jenssegers\\Mongodb' => array($vendorDir . '/jenssegers/mongodb/src'),
'Jenssegers\\Eloquent' => array($vendorDir . '/jenssegers/mongodb/src'),
'JakubOnderka\\PhpConsoleHighlighter' => array($vendorDir . '/jakub-onderka/php-console-highlighter/src'),
'JakubOnderka\\PhpConsoleColor' => array($vendorDir . '/jakub-onderka/php-console-color/src'),
'Doctrine\\Common\\Inflector\\' => array($vendorDir . '/doctrine/inflector/lib'),
......
......@@ -341,6 +341,14 @@ class ComposerStaticInitfbba5c913d657e1c2bf0c2ab261712a7
),
'J' =>
array (
'Jenssegers\\Mongodb' =>
array (
0 => __DIR__ . '/..' . '/jenssegers/mongodb/src',
),
'Jenssegers\\Eloquent' =>
array (
0 => __DIR__ . '/..' . '/jenssegers/mongodb/src',
),
'JakubOnderka\\PhpConsoleHighlighter' =>
array (
0 => __DIR__ . '/..' . '/jakub-onderka/php-console-highlighter/src',
......@@ -384,18 +392,23 @@ class ComposerStaticInitfbba5c913d657e1c2bf0c2ab261712a7
'App\\Http\\Controllers\\WebController' => __DIR__ . '/../..' . '/app/Http/Controllers/WebController.php',
'App\\Http\\Kernel' => __DIR__ . '/../..' . '/app/Http/Kernel.php',
'App\\Http\\Middleware\\CheckLogin' => __DIR__ . '/../..' . '/app/Http/Middleware/CheckLogin.php',
'App\\Http\\Middleware\\EnableCrossRequestMiddleware' => __DIR__ . '/../..' . '/app/Http/Middleware/EnableCrossRequestMiddleware.php',
'App\\Http\\Middleware\\JsonpCallback' => __DIR__ . '/../..' . '/app/Http/Middleware/JsonpCallback.php',
'App\\Http\\Middleware\\WmsVerification' => __DIR__ . '/../..' . '/app/Http/Middleware/WmsVerification.php',
'App\\Http\\Requests\\Request' => __DIR__ . '/../..' . '/app/Http/Requests/Request.php',
'App\\Jobs\\Job' => __DIR__ . '/../..' . '/app/Jobs/Job.php',
'App\\Model\\CmsModel' => __DIR__ . '/../..' . '/app/Model/CmsModel.php',
'App\\Model\\CommonModel' => __DIR__ . '/../..' . '/app/Model/CommonModel.php',
'App\\Model\\InquiryItemsAssignModel' => __DIR__ . '/../..' . '/app/Model/InquiryItemsAssignModel.php',
'App\\Model\\InquiryItemsModel' => __DIR__ . '/../..' . '/app/Model/InquiryItemsModel.php',
'App\\Model\\InquiryItemsReportModel' => __DIR__ . '/../..' . '/app/Model/InquiryItemsReportModel.php',
'App\\Model\\InquiryItemsUrgeModel' => __DIR__ . '/../..' . '/app/Model/InquiryItemsUrgeModel.php',
'App\\Model\\InquiryModel' => __DIR__ . '/../..' . '/app/Model/InquiryModel.php',
'App\\Model\\InquiryUsersModel' => __DIR__ . '/../..' . '/app/Model/InquiryUsersModel.php',
'App\\Model\\LoginModel' => __DIR__ . '/../..' . '/app/Model/LoginModel.php',
'App\\Model\\OpLogModel' => __DIR__ . '/../..' . '/app/Model/OpLogModel.php',
'App\\Model\\QuoteModel' => __DIR__ . '/../..' . '/app/Model/QuoteModel.php',
'App\\Model\\SearchModel' => __DIR__ . '/../..' . '/app/Model/SearchModel.php',
'App\\Model\\Server\\ExportModel' => __DIR__ . '/../..' . '/app/Model/ExportModel.php',
'App\\Model\\Server\\GoModel' => __DIR__ . '/../..' . '/app/Model/GoModel.php',
'App\\Model\\SupplierChannelComModel' => __DIR__ . '/../..' . '/app/Model/SupplierChannelComModel.php',
......@@ -1748,6 +1761,29 @@ class ComposerStaticInitfbba5c913d657e1c2bf0c2ab261712a7
'JakubOnderka\\PhpConsoleColor\\ConsoleColor' => __DIR__ . '/..' . '/jakub-onderka/php-console-color/src/JakubOnderka/PhpConsoleColor/ConsoleColor.php',
'JakubOnderka\\PhpConsoleColor\\InvalidStyleException' => __DIR__ . '/..' . '/jakub-onderka/php-console-color/src/JakubOnderka/PhpConsoleColor/InvalidStyleException.php',
'JakubOnderka\\PhpConsoleHighlighter\\Highlighter' => __DIR__ . '/..' . '/jakub-onderka/php-console-highlighter/src/JakubOnderka/PhpConsoleHighlighter/Highlighter.php',
'Jenssegers\\Eloquent\\Model' => __DIR__ . '/..' . '/jenssegers/mongodb/src/Jenssegers/Eloquent/Model.php',
'Jenssegers\\Mongodb\\Auth\\DatabaseTokenRepository' => __DIR__ . '/..' . '/jenssegers/mongodb/src/Jenssegers/Mongodb/Auth/DatabaseTokenRepository.php',
'Jenssegers\\Mongodb\\Auth\\PasswordResetServiceProvider' => __DIR__ . '/..' . '/jenssegers/mongodb/src/Jenssegers/Mongodb/Auth/PasswordResetServiceProvider.php',
'Jenssegers\\Mongodb\\Collection' => __DIR__ . '/..' . '/jenssegers/mongodb/src/Jenssegers/Mongodb/Collection.php',
'Jenssegers\\Mongodb\\Connection' => __DIR__ . '/..' . '/jenssegers/mongodb/src/Jenssegers/Mongodb/Connection.php',
'Jenssegers\\Mongodb\\Eloquent\\Builder' => __DIR__ . '/..' . '/jenssegers/mongodb/src/Jenssegers/Mongodb/Eloquent/Builder.php',
'Jenssegers\\Mongodb\\Eloquent\\HybridRelations' => __DIR__ . '/..' . '/jenssegers/mongodb/src/Jenssegers/Mongodb/Eloquent/HybridRelations.php',
'Jenssegers\\Mongodb\\Eloquent\\SoftDeletes' => __DIR__ . '/..' . '/jenssegers/mongodb/src/Jenssegers/Mongodb/Eloquent/SoftDeletes.php',
'Jenssegers\\Mongodb\\Model' => __DIR__ . '/..' . '/jenssegers/mongodb/src/Jenssegers/Mongodb/Model.php',
'Jenssegers\\Mongodb\\MongodbServiceProvider' => __DIR__ . '/..' . '/jenssegers/mongodb/src/Jenssegers/Mongodb/MongodbServiceProvider.php',
'Jenssegers\\Mongodb\\Query\\Builder' => __DIR__ . '/..' . '/jenssegers/mongodb/src/Jenssegers/Mongodb/Query/Builder.php',
'Jenssegers\\Mongodb\\Query\\Grammar' => __DIR__ . '/..' . '/jenssegers/mongodb/src/Jenssegers/Mongodb/Query/Grammar.php',
'Jenssegers\\Mongodb\\Query\\Processor' => __DIR__ . '/..' . '/jenssegers/mongodb/src/Jenssegers/Mongodb/Query/Processor.php',
'Jenssegers\\Mongodb\\Relations\\BelongsTo' => __DIR__ . '/..' . '/jenssegers/mongodb/src/Jenssegers/Mongodb/Relations/BelongsTo.php',
'Jenssegers\\Mongodb\\Relations\\BelongsToMany' => __DIR__ . '/..' . '/jenssegers/mongodb/src/Jenssegers/Mongodb/Relations/BelongsToMany.php',
'Jenssegers\\Mongodb\\Relations\\EmbedsMany' => __DIR__ . '/..' . '/jenssegers/mongodb/src/Jenssegers/Mongodb/Relations/EmbedsMany.php',
'Jenssegers\\Mongodb\\Relations\\EmbedsOne' => __DIR__ . '/..' . '/jenssegers/mongodb/src/Jenssegers/Mongodb/Relations/EmbedsOne.php',
'Jenssegers\\Mongodb\\Relations\\EmbedsOneOrMany' => __DIR__ . '/..' . '/jenssegers/mongodb/src/Jenssegers/Mongodb/Relations/EmbedsOneOrMany.php',
'Jenssegers\\Mongodb\\Relations\\HasMany' => __DIR__ . '/..' . '/jenssegers/mongodb/src/Jenssegers/Mongodb/Relations/HasMany.php',
'Jenssegers\\Mongodb\\Relations\\HasOne' => __DIR__ . '/..' . '/jenssegers/mongodb/src/Jenssegers/Mongodb/Relations/HasOne.php',
'Jenssegers\\Mongodb\\Relations\\MorphTo' => __DIR__ . '/..' . '/jenssegers/mongodb/src/Jenssegers/Mongodb/Relations/MorphTo.php',
'Jenssegers\\Mongodb\\Schema\\Blueprint' => __DIR__ . '/..' . '/jenssegers/mongodb/src/Jenssegers/Mongodb/Schema/Blueprint.php',
'Jenssegers\\Mongodb\\Schema\\Builder' => __DIR__ . '/..' . '/jenssegers/mongodb/src/Jenssegers/Mongodb/Schema/Builder.php',
'JsonSerializable' => __DIR__ . '/..' . '/nesbot/carbon/src/JsonSerializable.php',
'League\\Flysystem\\AdapterInterface' => __DIR__ . '/..' . '/league/flysystem/src/AdapterInterface.php',
'League\\Flysystem\\Adapter\\AbstractAdapter' => __DIR__ . '/..' . '/league/flysystem/src/Adapter/AbstractAdapter.php',
......
......@@ -845,6 +845,66 @@
"abandoned": "php-parallel-lint/php-console-highlighter"
},
{
"name": "jenssegers/mongodb",
"version": "v2.3.0",
"version_normalized": "2.3.0.0",
"source": {
"type": "git",
"url": "https://github.com/jenssegers/laravel-mongodb.git",
"reference": "22063084ea4370c3865b2364f56d0508f09ec4e8"
},
"dist": {
"type": "zip",
"url": "https://repo.huaweicloud.com/repository/php/dist/jenssegers/mongodb/jenssegers-mongodb-v2.3.0-22063084.zip",
"reference": "22063084ea4370c3865b2364f56d0508f09ec4e8",
"shasum": "2d4d44926acd4fe21db31e529f64b537c59242c7"
},
"require": {
"illuminate/container": "^5.1",
"illuminate/database": "^5.1",
"illuminate/events": "^5.1",
"illuminate/support": "^5.1"
},
"require-dev": {
"mockery/mockery": "^0.9",
"orchestra/testbench": "^3.1",
"phpunit/phpunit": "^4.0|^5.0",
"satooshi/php-coveralls": "^0.6"
},
"suggest": {
"jenssegers/mongodb-sentry": "Add Sentry support to Laravel-MongoDB",
"jenssegers/mongodb-session": "Add MongoDB session support to Laravel-MongoDB"
},
"time": "2016-02-03T23:25:16+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-0": {
"Jenssegers\\Mongodb": "src/",
"Jenssegers\\Eloquent": "src/"
}
},
"license": [
"MIT"
],
"authors": [
{
"name": "Jens Segers",
"homepage": "https://jenssegers.com"
}
],
"description": "A MongoDB based Eloquent model and Query builder for Laravel 4",
"homepage": "https://github.com/jenssegers/laravel-mongodb",
"keywords": [
"database",
"eloquent",
"laravel",
"model",
"mongo",
"mongodb"
]
},
{
"name": "jeremeamia/SuperClosure",
"version": "2.4.0",
"version_normalized": "2.4.0.0",
......
Laravel MongoDB
===============
[![Latest Stable Version](http://img.shields.io/github/release/jenssegers/laravel-mongodb.svg)](https://packagist.org/packages/jenssegers/mongodb) [![Total Downloads](http://img.shields.io/packagist/dm/jenssegers/mongodb.svg)](https://packagist.org/packages/jenssegers/mongodb) [![Build Status](http://img.shields.io/travis/jenssegers/laravel-mongodb.svg)](https://travis-ci.org/jenssegers/laravel-mongodb) [![Coverage Status](http://img.shields.io/coveralls/jenssegers/laravel-mongodb.svg)](https://coveralls.io/r/jenssegers/laravel-mongodb?branch=master) [![Donate](https://img.shields.io/badge/donate-paypal-blue.svg)](https://www.paypal.me/jenssegers)
An Eloquent model and Query builder with support for MongoDB, using the original Laravel API. *This library extends the original Laravel classes, so it uses exactly the same methods.*
Table of contents
-----------------
* [Installation](#installation)
* [Configuration](#configuration)
* [Eloquent](#eloquent)
* [Optional: Alias](#optional-alias)
* [Query Builder](#query-builder)
* [Schema](#schema)
* [Extensions](#extensions)
* [Troubleshooting](#troubleshooting)
* [Examples](#examples)
Installation
------------
Make sure you have the MongoDB PHP driver installed. You can find installation instructions at http://php.net/manual/en/mongo.installation.php
For Laravel 5, install the latest stable version using composer:
```
composer require jenssegers/mongodb
```
### Version Compatibility
Laravel | Package
:---------|:----------
4.2.x | 2.0.x
5.0.x | 2.1.x
5.1.x | 2.2.x
5.2.x | 2.3.x
And add the service provider in `config/app.php`:
```php
Jenssegers\Mongodb\MongodbServiceProvider::class,
```
For usage with [Lumen](http://lumen.laravel.com), add the service provider in `bootstrap/app.php`. In this file, you will also need to enable Eloquent. You must however ensure that your call to `$app->withEloquent();` is **below** where you have registered the `MongodbServiceProvider`:
```php
$app->register('Jenssegers\Mongodb\MongodbServiceProvider');
$app->withEloquent();
```
The service provider will register a mongodb database extension with the original database manager. There is no need to register additional facades or objects. When using mongodb connections, Laravel will automatically provide you with the corresponding mongodb objects.
For usage outside Laravel, check out the [Capsule manager](https://github.com/illuminate/database/blob/master/README.md) and add:
```php
$capsule->getDatabaseManager()->extend('mongodb', function($config)
{
return new Jenssegers\Mongodb\Connection($config);
});
```
Configuration
-------------
Change your default database connection name in `app/config/database.php`:
```php
'default' => env('DB_CONNECTION', 'mongodb'),
```
And add a new mongodb connection:
```php
'mongodb' => array(
'driver' => 'mongodb',
'host' => env('DB_HOST', 'localhost'),
'port' => env('DB_PORT', 27017),
'database' => env('DB_DATABASE', ''),
'username' => env('DB_USERNAME', ''),
'password' => env('DB_PASSWORD', ''),
'options' => array(
'db' => 'admin' // sets the authentication database required by mongo 3
)
),
```
You can connect to multiple servers or replica sets with the following configuration:
```php
'mongodb' => array(
'driver' => 'mongodb',
'host' => array('server1', 'server2'),
'port' => env('DB_PORT', 27017),
'database' => env('DB_DATABASE', ''),
'username' => env('DB_USERNAME', ''),
'password' => env('DB_PASSWORD', ''),
'options' => array('replicaSet' => 'replicaSetName')
),
```
Eloquent
--------
This package includes a MongoDB enabled Eloquent class that you can use to define models for corresponding collections.
```php
use Jenssegers\Mongodb\Model as Eloquent;
class User extends Eloquent {}
```
Note that we did not tell Eloquent which collection to use for the `User` model. Just like the original Eloquent, the lower-case, plural name of the class will be used as the table name unless another name is explicitly specified. You may specify a custom collection (alias for table) by defining a `collection` property on your model:
```php
use Jenssegers\Mongodb\Model as Eloquent;
class User extends Eloquent {
protected $collection = 'users_collection';
}
```
**NOTE:** Eloquent will also assume that each collection has a primary key column named id. You may define a `primaryKey` property to override this convention. Likewise, you may define a `connection` property to override the name of the database connection that should be used when utilizing the model.
```php
use Jenssegers\Mongodb\Model as Eloquent;
class MyModel extends Eloquent {
protected $connection = 'mongodb';
}
```
Everything else works just like the original Eloquent model. Read more about the Eloquent on http://laravel.com/docs/eloquent
### Optional: Alias
You may also register an alias for the MongoDB model by adding the following to the alias array in `app/config/app.php`:
```php
'Moloquent' => 'Jenssegers\Mongodb\Model',
```
This will allow you to use the registered alias like:
```php
class MyModel extends Moloquent {}
```
Query Builder
-------------
The database driver plugs right into the original query builder. When using mongodb connections, you will be able to build fluent queries to perform database operations. For your convenience, there is a `collection` alias for `table` as well as some additional mongodb specific operators/operations.
```php
$users = DB::collection('users')->get();
$user = DB::collection('users')->where('name', 'John')->first();
```
If you did not change your default database connection, you will need to specify it when querying.
```php
$user = DB::connection('mongodb')->collection('users')->get();
```
Read more about the query builder on http://laravel.com/docs/queries
Schema
------
The database driver also has (limited) schema builder support. You can easily manipulate collections and set indexes:
```php
Schema::create('users', function($collection)
{
$collection->index('name');
$collection->unique('email');
});
```
Supported operations are:
- create and drop
- collection
- hasCollection
- index and dropIndex (compound indexes supported as well)
- unique
- background, sparse, expire (MongoDB specific)
All other (unsupported) operations are implemented as dummy pass-through methods, because MongoDB does not use a predefined schema. Read more about the schema builder on http://laravel.com/docs/schema
Extensions
----------
### Auth
If you want to use Laravel's native Auth functionality, register this included service provider:
```php
'Jenssegers\Mongodb\Auth\PasswordResetServiceProvider',
```
This service provider will slightly modify the internal DatabaseReminderRepository to add support for MongoDB based password reminders. If you don't use password reminders, you don't have to register this service provider and everything else should work just fine.
### Sentry
If you want to use this library with [Sentry](https://cartalyst.com/manual/sentry), then check out https://github.com/jenssegers/Laravel-MongoDB-Sentry
### Sessions
The MongoDB session driver is available in a separate package, check out https://github.com/jenssegers/Laravel-MongoDB-Session
Troubleshooting
---------------
#### Class 'MongoClient' not found in ...
The `MongoClient` class is part of the MongoDB PHP driver. Usually, this error means that you forgot to install, or did not install this driver correctly. You can find installation instructions for this driver at http://php.net/manual/en/mongo.installation.php.
To check if you have installed the driver correctly, run the following command:
```sh
$ php -i | grep 'Mongo'
MongoDB Support => enabled
```
#### Argument 2 passed to Illuminate\Database\Query\Builder::__construct() must be an instance of Illuminate\Database\Query\Grammars\Grammar, null given
To solve this, you will need to check two things. First check if your model is extending the correct class; this class should be `Jenssegers\Mongodb\Model`. Secondly, check if your model is using a MongoDB connection. If you did not change the default database connection in your database configuration file, you need to specify the MongoDB enabled connection. This is what your class should look like if you did not set up an alias and change the default database connection:
```php
use Jenssegers\Mongodb\Model as Eloquent;
class User extends Eloquent {
protected $connection = 'mongodb';
}
```
Examples
--------
### Basic Usage
**Retrieving All Models**
```php
$users = User::all();
```
**Retrieving A Record By Primary Key**
```php
$user = User::find('517c43667db388101e00000f');
```
**Wheres**
```php
$users = User::where('votes', '>', 100)->take(10)->get();
```
**Or Statements**
```php
$users = User::where('votes', '>', 100)->orWhere('name', 'John')->get();
```
**And Statements**
```php
$users = User::where('votes', '>', 100)->where('name', '=', 'John')->get();
```
**Using Where In With An Array**
```php
$users = User::whereIn('age', array(16, 18, 20))->get();
```
When using `whereNotIn` objects will be returned if the field is non existent. Combine with `whereNotNull('age')` to leave out those documents.
**Using Where Between**
```php
$users = User::whereBetween('votes', array(1, 100))->get();
```
**Where null**
```php
$users = User::whereNull('updated_at')->get();
```
**Order By**
```php
$users = User::orderBy('name', 'desc')->get();
```
**Offset & Limit**
```php
$users = User::skip(10)->take(5)->get();
```
**Distinct**
Distinct requires a field for which to return the distinct values.
```php
$users = User::distinct()->get(array('name'));
// or
$users = User::distinct('name')->get();
```
Distinct can be combined with **where**:
```php
$users = User::where('active', true)->distinct('name')->get();
```
**Advanced Wheres**
```php
$users = User::where('name', '=', 'John')->orWhere(function($query)
{
$query->where('votes', '>', 100)
->where('title', '<>', 'Admin');
})
->get();
```
**Group By**
Selected columns that are not grouped will be aggregated with the $last function.
```php
$users = Users::groupBy('title')->get(array('title', 'name'));
```
**Aggregation**
*Aggregations are only available for MongoDB versions greater than 2.2.*
```php
$total = Order::count();
$price = Order::max('price');
$price = Order::min('price');
$price = Order::avg('price');
$total = Order::sum('price');
```
Aggregations can be combined with **where**:
```php
$sold = Orders::where('sold', true)->sum('price');
```
**Like**
```php
$user = Comment::where('body', 'like', '%spam%')->get();
```
**Incrementing or decrementing a value of a column**
Perform increments or decrements (default 1) on specified attributes:
```php
User::where('name', 'John Doe')->increment('age');
User::where('name', 'Jaques')->decrement('weight', 50);
```
The number of updated objects is returned:
```php
$count = User->increment('age');
```
You may also specify additional columns to update:
```php
User::where('age', '29')->increment('age', 1, array('group' => 'thirty something'));
User::where('bmi', 30)->decrement('bmi', 1, array('category' => 'overweight'));
```
**Soft deleting**
When soft deleting a model, it is not actually removed from your database. Instead, a deleted_at timestamp is set on the record. To enable soft deletes for a model, apply the SoftDeletingTrait to the model:
```php
use Jenssegers\Mongodb\Eloquent\SoftDeletes;
class User extends Eloquent {
use SoftDeletes;
protected $dates = ['deleted_at'];
}
```
For more information check http://laravel.com/docs/eloquent#soft-deleting
### MongoDB specific operators
**Exists**
Matches documents that have the specified field.
```php
User::where('age', 'exists', true)->get();
```
**All**
Matches arrays that contain all elements specified in the query.
```php
User::where('roles', 'all', array('moderator', 'author'))->get();
```
**Size**
Selects documents if the array field is a specified size.
```php
User::where('tags', 'size', 3)->get();
```
**Regex**
Selects documents where values match a specified regular expression.
```php
User::where('name', 'regex', new MongoRegex("/.*doe/i"))->get();
```
**NOTE:** you can also use the Laravel regexp operations. These are a bit more flexible and will automatically convert your regular expression string to a MongoRegex object.
```php
User::where('name', 'regexp', '/.*doe/i'))->get();
```
And the inverse:
```php
User::where('name', 'not regexp', '/.*doe/i'))->get();
```
**Type**
Selects documents if a field is of the specified type. For more information check: http://docs.mongodb.org/manual/reference/operator/query/type/#op._S_type
```php
User::where('age', 'type', 2)->get();
```
**Mod**
Performs a modulo operation on the value of a field and selects documents with a specified result.
```php
User::where('age', 'mod', array(10, 0))->get();
```
**Where**
Matches documents that satisfy a JavaScript expression. For more information check http://docs.mongodb.org/manual/reference/operator/query/where/#op._S_where
### Inserts, updates and deletes
Inserting, updating and deleting records works just like the original Eloquent.
**Saving a new model**
```php
$user = new User;
$user->name = 'John';
$user->save();
```
You may also use the create method to save a new model in a single line:
```php
User::create(array('name' => 'John'));
```
**Updating a model**
To update a model, you may retrieve it, change an attribute, and use the save method.
```php
$user = User::first();
$user->email = 'john@foo.com';
$user->save();
```
*There is also support for upsert operations, check https://github.com/jenssegers/laravel-mongodb#mongodb-specific-operations*
**Deleting a model**
To delete a model, simply call the delete method on the instance:
```php
$user = User::first();
$user->delete();
```
Or deleting a model by its key:
```php
User::destroy('517c43667db388101e00000f');
```
For more information about model manipulation, check http://laravel.com/docs/eloquent#insert-update-delete
### Dates
Eloquent allows you to work with Carbon/DateTime objects instead of MongoDate objects. Internally, these dates will be converted to MongoDate objects when saved to the database. If you wish to use this functionality on non-default date fields you will need to manually specify them as described here: http://laravel.com/docs/eloquent#date-mutators
Example:
```php
use Jenssegers\Mongodb\Model as Eloquent;
class User extends Eloquent {
protected $dates = array('birthday');
}
```
Which allows you to execute queries like:
```php
$users = User::where('birthday', '>', new DateTime('-18 years'))->get();
```
### Relations
Supported relations are:
- hasOne
- hasMany
- belongsTo
- belongsToMany
Example:
```php
use Jenssegers\Mongodb\Model as Eloquent;
class User extends Eloquent {
public function items()
{
return $this->hasMany('Item');
}
}
```
And the inverse relation:
```php
use Jenssegers\Mongodb\Model as Eloquent;
class Item extends Eloquent {
public function user()
{
return $this->belongsTo('User');
}
}
```
The belongsToMany relation will not use a pivot "table", but will push id's to a __related_ids__ attribute instead. This makes the second parameter for the belongsToMany method useless. If you want to define custom keys for your relation, set it to `null`:
```php
use Jenssegers\Mongodb\Model as Eloquent;
class User extends Eloquent {
public function groups()
{
return $this->belongsToMany('Group', null, 'users', 'groups');
}
}
```
Other relations are not yet supported, but may be added in the future. Read more about these relations on http://laravel.com/docs/eloquent#relationships
### EmbedsMany Relations
If you want to embed models, rather than referencing them, you can use the `embedsMany` relation. This relation is similar to the `hasMany` relation, but embeds the models inside the parent object.
```php
use Jenssegers\Mongodb\Model as Eloquent;
class User extends Eloquent {
public function books()
{
return $this->embedsMany('Book');
}
}
```
You access the embedded models through the dynamic property:
```php
$books = User::first()->books;
```
The inverse relation is auto*magically* available, you don't need to define this reverse relation.
```php
$user = $book->user;
```
Inserting and updating embedded models works similar to the `hasMany` relation:
```php
$book = new Book(array('title' => 'A Game of Thrones'));
$user = User::first();
$book = $user->books()->save($book);
// or
$book = $user->books()->create(array('title' => 'A Game of Thrones'))
```
You can update embedded models using their `save` method (available since release 2.0.0):
```php
$book = $user->books()->first();
$book->title = 'A Game of Thrones';
$book->save();
```
You can remove an embedded model by using the `destroy` method on the relation, or the `delete` method on the model (available since release 2.0.0):
```php
$book = $user->books()->first();
$book->delete();
// or
$user->books()->destroy($book);
```
If you want to add or remove an embedded model, without touching the database, you can use the `associate` and `dissociate` methods. To eventually write the changes to the database, save the parent object:
```php
$user->books()->associate($book);
$user->save();
```
Like other relations, embedsMany assumes the local key of the relationship based on the model name. You can override the default local key by passing a second argument to the embedsMany method:
```php
return $this->embedsMany('Book', 'local_key');
```
Embedded relations will return a Collection of embedded items instead of a query builder. To allow a more query-like behavior, a modified version of the Collection class is used, with support for the following **additional** operations:
- where($key, $operator, $value)
- whereIn($key, $values) and whereNotIn($key, $values)
- whereBetween($key, $values) and whereNotBetween($key, $values)
- whereNull($key) and whereNotNull($key)
- orderBy($key, $direction)
- oldest() and latest()
- limit($value)
- offset($value)
- skip($value)
This allows you to execute simple queries on the collection results:
```php
$books = $user->books()->where('rating', '>', 5)->orderBy('title')->get();
```
**Note:** Because embedded models are not stored in a separate collection, you can not query all of embedded models. You will always have to access them through the parent model.
### EmbedsOne Relations
The embedsOne relation is similar to the EmbedsMany relation, but only embeds a single model.
```php
use Jenssegers\Mongodb\Model as Eloquent;
class Book extends Eloquent {
public function author()
{
return $this->embedsOne('Author');
}
}
```
You access the embedded models through the dynamic property:
```php
$author = Book::first()->author;
```
Inserting and updating embedded models works similar to the `hasOne` relation:
```php
$author = new Author(array('name' => 'John Doe'));
$book = Books::first();
$author = $book->author()->save($author);
// or
$author = $book->author()->create(array('name' => 'John Doe'));
```
You can update the embedded model using the `save` method (available since release 2.0.0):
```php
$author = $book->author;
$author->name = 'Jane Doe';
$author->save();
```
You can replace the embedded model with a new model like this:
```php
$newAuthor = new Author(array('name' => 'Jane Doe'));
$book->author()->save($newAuthor);
```
### MySQL Relations
If you're using a hybrid MongoDB and SQL setup, you're in luck! The model will automatically return a MongoDB- or SQL-relation based on the type of the related model. Of course, if you want this functionality to work both ways, your SQL-models will need to extend `Jenssegers\Eloquent\Model`. Note that this functionality only works for hasOne, hasMany and belongsTo relations.
Example SQL-based User model:
```php
use Jenssegers\Eloquent\Model as Eloquent;
class User extends Eloquent {
protected $connection = 'mysql';
public function messages()
{
return $this->hasMany('Message');
}
}
```
And the Mongodb-based Message model:
```php
use Jenssegers\Mongodb\Model as Eloquent;
class Message extends Eloquent {
protected $connection = 'mongodb';
public function user()
{
return $this->belongsTo('User');
}
}
```
### Raw Expressions
These expressions will be injected directly into the query.
```php
User::whereRaw(array('age' => array('$gt' => 30, '$lt' => 40)))->get();
```
You can also perform raw expressions on the internal MongoCollection object. If this is executed on the model class, it will return a collection of models. If this is executed on the query builder, it will return the original response.
```php
// Returns a collection of User models.
$models = User::raw(function($collection)
{
return $collection->find();
});
// Returns the original MongoCursor.
$cursor = DB::collection('users')->raw(function($collection)
{
return $collection->find();
});
```
Optional: if you don't pass a closure to the raw method, the internal MongoCollection object will be accessible:
```php
$model = User::raw()->findOne(array('age' => array('$lt' => 18)));
```
The internal MongoClient and MongoDB objects can be accessed like this:
```php
$client = DB::getMongoClient();
$db = DB::getMongoDB();
```
### MongoDB specific operations
**Cursor timeout**
To prevent MongoCursorTimeout exceptions, you can manually set a timeout value that will be applied to the cursor:
```php
DB::collection('users')->timeout(-1)->get();
```
**Upsert**
Update or insert a document. Additional options for the update method are passed directly to the native update method.
```php
DB::collection('users')->where('name', 'John')
->update($data, array('upsert' => true));
```
**Projections**
You can apply projections to your queries using the `project` method.
```php
DB::collection('items')->project(array('tags' => array('$slice' => 1)))->get();
```
**Projections with Pagination**
```php
$limit = 25;
$projections = array('id', 'name');
DB::collection('items')->paginate($limit, $projections);
```
**Push**
Add an items to an array.
```php
DB::collection('users')->where('name', 'John')->push('items', 'boots');
DB::collection('users')->where('name', 'John')->push('messages', array('from' => 'Jane Doe', 'message' => 'Hi John'));
```
If you don't want duplicate items, set the third parameter to `true`:
```php
DB::collection('users')->where('name', 'John')->push('items', 'boots', true);
```
**Pull**
Remove an item from an array.
```php
DB::collection('users')->where('name', 'John')->pull('items', 'boots');
DB::collection('users')->where('name', 'John')->pull('messages', array('from' => 'Jane Doe', 'message' => 'Hi John'));
```
**Unset**
Remove one or more fields from a document.
```php
DB::collection('users')->where('name', 'John')->unset('note');
```
You can also perform an unset on a model.
```php
$user = User::where('name', 'John')->first();
$user->unset('note');
```
### Query Caching
You may easily cache the results of a query using the remember method:
```php
$users = User::remember(10)->get();
```
*From: http://laravel.com/docs/queries#caching-queries*
### Query Logging
By default, Laravel keeps a log in memory of all queries that have been run for the current request. However, in some cases, such as when inserting a large number of rows, this can cause the application to use excess memory. To disable the log, you may use the `disableQueryLog` method:
```php
DB::connection()->disableQueryLog();
```
*From: http://laravel.com/docs/database#query-logging*
{
"name": "jenssegers/mongodb",
"description": "A MongoDB based Eloquent model and Query builder for Laravel 4",
"keywords": ["laravel","eloquent","mongodb","mongo","database","model"],
"homepage": "https://github.com/jenssegers/laravel-mongodb",
"authors": [
{
"name": "Jens Segers",
"homepage": "https://jenssegers.com"
}
],
"license" : "MIT",
"require": {
"illuminate/support": "^5.1",
"illuminate/container": "^5.1",
"illuminate/database": "^5.1",
"illuminate/events": "^5.1"
},
"require-dev": {
"phpunit/phpunit": "^4.0|^5.0",
"orchestra/testbench": "^3.1",
"mockery/mockery": "^0.9",
"satooshi/php-coveralls": "^0.6"
},
"autoload": {
"psr-0": {
"Jenssegers\\Mongodb": "src/",
"Jenssegers\\Eloquent": "src/"
}
},
"autoload-dev": {
"classmap": [
"tests/TestCase.php",
"tests/models",
"tests/seeds"
]
},
"suggest": {
"jenssegers/mongodb-session": "Add MongoDB session support to Laravel-MongoDB",
"jenssegers/mongodb-sentry": "Add Sentry support to Laravel-MongoDB"
}
}
<?php namespace Jenssegers\Eloquent;
use Jenssegers\Mongodb\Eloquent\HybridRelations;
abstract class Model extends \Illuminate\Database\Eloquent\Model
{
use HybridRelations;
}
<?php namespace Jenssegers\Mongodb\Auth;
use DateTime;
use MongoDate;
class DatabaseTokenRepository extends \Illuminate\Auth\Passwords\DatabaseTokenRepository
{
/**
* Build the record payload for the table.
*
* @param string $email
* @param string $token
* @return array
*/
protected function getPayload($email, $token)
{
return ['email' => $email, 'token' => $token, 'created_at' => new MongoDate];
}
/**
* Determine if the token has expired.
*
* @param array $token
* @return bool
*/
protected function tokenExpired($token)
{
// Convert MongoDate to a date string.
if ($token['created_at'] instanceof MongoDate) {
$date = new DateTime;
$date->setTimestamp($token['created_at']->sec);
$token['created_at'] = $date->format('Y-m-d H:i:s');
} elseif (is_array($token['created_at']) and isset($token['created_at']['date'])) {
$token['created_at'] = $token['created_at']['date'];
}
return parent::tokenExpired($token);
}
}
<?php namespace Jenssegers\Mongodb\Auth;
use Jenssegers\Mongodb\Auth\DatabaseTokenRepository as DbRepository;
class PasswordResetServiceProvider extends \Illuminate\Auth\Passwords\PasswordResetServiceProvider
{
/**
* Register the token repository implementation.
*
* @return void
*/
protected function registerTokenRepository()
{
$this->app->singleton('auth.password.tokens', function ($app) {
$connection = $app['db']->connection();
// The database token repository is an implementation of the token repository
// interface, and is responsible for the actual storing of auth tokens and
// their e-mail addresses. We will inject this table and hash key to it.
$table = $app['config']['auth.password.table'];
$key = $app['config']['app.key'];
$expire = $app['config']->get('auth.password.expire', 60);
return new DbRepository($connection, $table, $key, $expire);
});
}
}
<?php namespace Jenssegers\Mongodb;
use Exception;
use MongoCollection;
class Collection
{
/**
* The connection instance.
*
* @var Connection
*/
protected $connection;
/**
* The MongoCollection instance..
*
* @var MongoCollection
*/
protected $collection;
/**
* Constructor.
*/
public function __construct(Connection $connection, MongoCollection $collection)
{
$this->connection = $connection;
$this->collection = $collection;
}
/**
* Handle dynamic method calls.
*
* @param string $method
* @param array $parameters
* @return mixed
*/
public function __call($method, $parameters)
{
$start = microtime(true);
$result = call_user_func_array([$this->collection, $method], $parameters);
if ($this->connection->logging()) {
// Once we have run the query we will calculate the time that it took to run and
// then log the query, bindings, and execution time so we will report them on
// the event that the developer needs them. We'll log time in milliseconds.
$time = $this->connection->getElapsedTime($start);
$query = [];
// Convert the query paramters to a json string.
foreach ($parameters as $parameter) {
try {
$query[] = json_encode($parameter);
} catch (Exception $e) {
$query[] = '{...}';
}
}
$queryString = $this->collection->getName() . '.' . $method . '(' . implode(',', $query) . ')';
$this->connection->logQuery($queryString, [], $time);
}
return $result;
}
}
<?php namespace Jenssegers\Mongodb;
use MongoClient;
class Connection extends \Illuminate\Database\Connection
{
/**
* The MongoDB database handler.
*
* @var MongoDB
*/
protected $db;
/**
* The MongoClient connection handler.
*
* @var MongoClient
*/
protected $connection;
/**
* Create a new database connection instance.
*
* @param array $config
*/
public function __construct(array $config)
{
$this->config = $config;
// Build the connection string
$dsn = $this->getDsn($config);
// You can pass options directly to the MongoClient constructor
$options = array_get($config, 'options', []);
// Create the connection
$this->connection = $this->createConnection($dsn, $config, $options);
// Select database
$this->db = $this->connection->{$config['database']};
$this->useDefaultPostProcessor();
}
/**
* Get the default post processor instance.
*
* @return Query\Processor
*/
protected function getDefaultPostProcessor()
{
return new Query\Processor;
}
/**
* Begin a fluent query against a database collection.
*
* @param string $collection
* @return QueryBuilder
*/
public function collection($collection)
{
$processor = $this->getPostProcessor();
$query = new Query\Builder($this, $processor);
return $query->from($collection);
}
/**
* Begin a fluent query against a database collection.
*
* @param string $table
* @return QueryBuilder
*/
public function table($table)
{
return $this->collection($table);
}
/**
* Get a MongoDB collection.
*
* @param string $name
* @return MongoDB
*/
public function getCollection($name)
{
return new Collection($this, $this->db->selectCollection($name));
}
/**
* Get a schema builder instance for the connection.
*
* @return Schema\Builder
*/
public function getSchemaBuilder()
{
return new Schema\Builder($this);
}
/**
* Get the MongoDB database object.
*
* @return MongoDB
*/
public function getMongoDB()
{
return $this->db;
}
/**
* return MongoClient object.
*
* @return MongoClient
*/
public function getMongoClient()
{
return $this->connection;
}
/**
* Create a new MongoClient connection.
*
* @param string $dsn
* @param array $config
* @param array $options
* @return MongoClient
*/
protected function createConnection($dsn, array $config, array $options)
{
// Add credentials as options, this makes sure the connection will not fail if
// the username or password contains strange characters.
if (! empty($config['username'])) {
$options['username'] = $config['username'];
}
if (! empty($config['password'])) {
$options['password'] = $config['password'];
}
// By default driver options is an empty array.
$driverOptions = [];
if (isset($config['driver_options']) && is_array($config['driver_options'])) {
$driverOptions = $config['driver_options'];
}
return new MongoClient($dsn, $options, $driverOptions);
}
/**
* Disconnect from the underlying MongoClient connection.
*/
public function disconnect()
{
$this->connection->close();
}
/**
* Create a DSN string from a configuration.
*
* @param array $config
* @return string
*/
protected function getDsn(array $config)
{
// First we will create the basic DSN setup as well as the port if it is in
// in the configuration options. This will give us the basic DSN we will
// need to establish the MongoClient and return them back for use.
extract($config);
// Check if the user passed a complete dsn to the configuration.
if (! empty($dsn)) {
return $dsn;
}
// Treat host option as array of hosts
$hosts = is_array($host) ? $host : [$host];
foreach ($hosts as &$host) {
// Check if we need to add a port to the host
if (strpos($host, ':') === false and isset($port)) {
$host = "{$host}:{$port}";
}
}
// The database name needs to be in the connection string, otherwise it will
// authenticate to the admin database, which may result in permission errors.
return "mongodb://" . implode(',', $hosts) . "/{$database}";
}
/**
* Get the elapsed time since a given starting point.
*
* @param int $start
* @return float
*/
public function getElapsedTime($start)
{
return parent::getElapsedTime($start);
}
/**
* Get the PDO driver name.
*
* @return string
*/
public function getDriverName()
{
return 'mongodb';
}
/**
* Dynamically pass methods to the connection.
*
* @param string $method
* @param array $parameters
* @return mixed
*/
public function __call($method, $parameters)
{
return call_user_func_array([$this->db, $method], $parameters);
}
}
<?php namespace Jenssegers\Mongodb\Eloquent;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Eloquent\Relations\Relation;
use MongoCursor;
class Builder extends EloquentBuilder
{
/**
* The methods that should be returned from query builder.
*
* @var array
*/
protected $passthru = [
'toSql', 'lists', 'insert', 'insertGetId', 'pluck',
'count', 'min', 'max', 'avg', 'sum', 'exists', 'push', 'pull',
];
/**
* Update a record in the database.
*
* @param array $values
* @return int
*/
public function update(array $values)
{
// Intercept operations on embedded models and delegate logic
// to the parent relation instance.
if ($relation = $this->model->getParentRelation()) {
$relation->performUpdate($this->model, $values);
return 1;
}
return parent::update($values);
}
/**
* Insert a new record into the database.
*
* @param array $values
* @return bool
*/
public function insert(array $values)
{
// Intercept operations on embedded models and delegate logic
// to the parent relation instance.
if ($relation = $this->model->getParentRelation()) {
$relation->performInsert($this->model, $values);
return true;
}
return parent::insert($values);
}
/**
* Insert a new record and get the value of the primary key.
*
* @param array $values
* @param string $sequence
* @return int
*/
public function insertGetId(array $values, $sequence = null)
{
// Intercept operations on embedded models and delegate logic
// to the parent relation instance.
if ($relation = $this->model->getParentRelation()) {
$relation->performInsert($this->model, $values);
return $this->model->getKey();
}
return parent::insertGetId($values, $sequence);
}
/**
* Delete a record from the database.
*
* @return mixed
*/
public function delete()
{
// Intercept operations on embedded models and delegate logic
// to the parent relation instance.
if ($relation = $this->model->getParentRelation()) {
$relation->performDelete($this->model);
return $this->model->getKey();
}
return parent::delete();
}
/**
* Increment a column's value by a given amount.
*
* @param string $column
* @param int $amount
* @param array $extra
* @return int
*/
public function increment($column, $amount = 1, array $extra = [])
{
// Intercept operations on embedded models and delegate logic
// to the parent relation instance.
if ($relation = $this->model->getParentRelation()) {
$value = $this->model->{$column};
// When doing increment and decrements, Eloquent will automatically
// sync the original attributes. We need to change the attribute
// temporary in order to trigger an update query.
$this->model->{$column} = null;
$this->model->syncOriginalAttribute($column);
$result = $this->model->update([$column => $value]);
return $result;
}
return parent::increment($column, $amount, $extra);
}
/**
* Decrement a column's value by a given amount.
*
* @param string $column
* @param int $amount
* @param array $extra
* @return int
*/
public function decrement($column, $amount = 1, array $extra = [])
{
// Intercept operations on embedded models and delegate logic
// to the parent relation instance.
if ($relation = $this->model->getParentRelation()) {
$value = $this->model->{$column};
// When doing increment and decrements, Eloquent will automatically
// sync the original attributes. We need to change the attribute
// temporary in order to trigger an update query.
$this->model->{$column} = null;
$this->model->syncOriginalAttribute($column);
return $this->model->update([$column => $value]);
}
return parent::decrement($column, $amount, $extra);
}
/**
* Add the "has" condition where clause to the query.
*
* @param \Illuminate\Database\Eloquent\Builder $hasQuery
* @param \Illuminate\Database\Eloquent\Relations\Relation $relation
* @param string $operator
* @param int $count
* @param string $boolean
* @return \Illuminate\Database\Eloquent\Builder
*/
protected function addHasWhere(EloquentBuilder $hasQuery, Relation $relation, $operator, $count, $boolean)
{
$query = $hasQuery->getQuery();
// Get the number of related objects for each possible parent.
$relationCount = array_count_values($query->lists($relation->getHasCompareKey()));
// Remove unwanted related objects based on the operator and count.
$relationCount = array_filter($relationCount, function ($counted) use ($count, $operator) {
// If we are comparing to 0, we always need all results.
if ($count == 0) {
return true;
}
switch ($operator) {
case '>=':
case '<':
return $counted >= $count;
case '>':
case '<=':
return $counted > $count;
case '=':
case '!=':
return $counted == $count;
}
});
// If the operator is <, <= or !=, we will use whereNotIn.
$not = in_array($operator, ['<', '<=', '!=']);
// If we are comparing to 0, we need an additional $not flip.
if ($count == 0) {
$not = !$not;
}
// All related ids.
$relatedIds = array_keys($relationCount);
// Add whereIn to the query.
return $this->whereIn($this->model->getKeyName(), $relatedIds, $boolean, $not);
}
/**
* Create a raw database expression.
*
* @param closure $expression
* @return mixed
*/
public function raw($expression = null)
{
// Get raw results from the query builder.
$results = $this->query->raw($expression);
// Convert MongoCursor results to a collection of models.
if ($results instanceof MongoCursor) {
$results = iterator_to_array($results, false);
return $this->model->hydrate($results);
}
// The result is a single object.
elseif (is_array($results) and array_key_exists('_id', $results)) {
$model = $this->model->newFromBuilder($results);
$model->setConnection($this->model->getConnection());
return $model;
}
return $results;
}
}
<?php namespace Jenssegers\Mongodb\Eloquent;
use Illuminate\Database\Eloquent\Relations\MorphMany;
use Illuminate\Database\Eloquent\Relations\MorphOne;
use Illuminate\Support\Str;
use Jenssegers\Mongodb\Model;
use Jenssegers\Mongodb\Relations\BelongsTo;
use Jenssegers\Mongodb\Relations\BelongsToMany;
use Jenssegers\Mongodb\Relations\HasMany;
use Jenssegers\Mongodb\Relations\HasOne;
use Jenssegers\Mongodb\Relations\MorphTo;
trait HybridRelations
{
/**
* Define a one-to-one relationship.
*
* @param string $related
* @param string $foreignKey
* @param string $localKey
* @return \Illuminate\Database\Eloquent\Relations\HasOne
*/
public function hasOne($related, $foreignKey = null, $localKey = null)
{
// Check if it is a relation with an original model.
if (! is_subclass_of($related, 'Jenssegers\Mongodb\Model')) {
return parent::hasOne($related, $foreignKey, $localKey);
}
$foreignKey = $foreignKey ?: $this->getForeignKey();
$instance = new $related;
$localKey = $localKey ?: $this->getKeyName();
return new HasOne($instance->newQuery(), $this, $foreignKey, $localKey);
}
/**
* Define a polymorphic one-to-one relationship.
*
* @param string $related
* @param string $name
* @param string $type
* @param string $id
* @param string $localKey
* @return \Illuminate\Database\Eloquent\Relations\MorphOne
*/
public function morphOne($related, $name, $type = null, $id = null, $localKey = null)
{
// Check if it is a relation with an original model.
if (! is_subclass_of($related, 'Jenssegers\Mongodb\Model')) {
return parent::morphOne($related, $name, $type, $id, $localKey);
}
$instance = new $related;
list($type, $id) = $this->getMorphs($name, $type, $id);
$table = $instance->getTable();
$localKey = $localKey ?: $this->getKeyName();
return new MorphOne($instance->newQuery(), $this, $type, $id, $localKey);
}
/**
* Define a one-to-many relationship.
*
* @param string $related
* @param string $foreignKey
* @param string $localKey
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function hasMany($related, $foreignKey = null, $localKey = null)
{
// Check if it is a relation with an original model.
if (! is_subclass_of($related, 'Jenssegers\Mongodb\Model')) {
return parent::hasMany($related, $foreignKey, $localKey);
}
$foreignKey = $foreignKey ?: $this->getForeignKey();
$instance = new $related;
$localKey = $localKey ?: $this->getKeyName();
return new HasMany($instance->newQuery(), $this, $foreignKey, $localKey);
}
/**
* Define a polymorphic one-to-many relationship.
*
* @param string $related
* @param string $name
* @param string $type
* @param string $id
* @param string $localKey
* @return \Illuminate\Database\Eloquent\Relations\MorphMany
*/
public function morphMany($related, $name, $type = null, $id = null, $localKey = null)
{
// Check if it is a relation with an original model.
if (! is_subclass_of($related, 'Jenssegers\Mongodb\Model')) {
return parent::morphMany($related, $name, $type, $id, $localKey);
}
$instance = new $related;
// Here we will gather up the morph type and ID for the relationship so that we
// can properly query the intermediate table of a relation. Finally, we will
// get the table and create the relationship instances for the developers.
list($type, $id) = $this->getMorphs($name, $type, $id);
$table = $instance->getTable();
$localKey = $localKey ?: $this->getKeyName();
return new MorphMany($instance->newQuery(), $this, $type, $id, $localKey);
}
/**
* Define an inverse one-to-one or many relationship.
*
* @param string $related
* @param string $foreignKey
* @param string $otherKey
* @param string $relation
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function belongsTo($related, $foreignKey = null, $otherKey = null, $relation = null)
{
// If no relation name was given, we will use this debug backtrace to extract
// the calling method's name and use that as the relationship name as most
// of the time this will be what we desire to use for the relationships.
if (is_null($relation)) {
list($current, $caller) = debug_backtrace(false, 2);
$relation = $caller['function'];
}
// Check if it is a relation with an original model.
if (! is_subclass_of($related, 'Jenssegers\Mongodb\Model')) {
return parent::belongsTo($related, $foreignKey, $otherKey, $relation);
}
// If no foreign key was supplied, we can use a backtrace to guess the proper
// foreign key name by using the name of the relationship function, which
// when combined with an "_id" should conventionally match the columns.
if (is_null($foreignKey)) {
$foreignKey = Str::snake($relation) . '_id';
}
$instance = new $related;
// Once we have the foreign key names, we'll just create a new Eloquent query
// for the related models and returns the relationship instance which will
// actually be responsible for retrieving and hydrating every relations.
$query = $instance->newQuery();
$otherKey = $otherKey ?: $instance->getKeyName();
return new BelongsTo($query, $this, $foreignKey, $otherKey, $relation);
}
/**
* Define a polymorphic, inverse one-to-one or many relationship.
*
* @param string $name
* @param string $type
* @param string $id
* @return \Illuminate\Database\Eloquent\Relations\MorphTo
*/
public function morphTo($name = null, $type = null, $id = null)
{
// If no name is provided, we will use the backtrace to get the function name
// since that is most likely the name of the polymorphic interface. We can
// use that to get both the class and foreign key that will be utilized.
if (is_null($name)) {
list($current, $caller) = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
$name = Str::snake($caller['function']);
}
list($type, $id) = $this->getMorphs($name, $type, $id);
// If the type value is null it is probably safe to assume we're eager loading
// the relationship. When that is the case we will pass in a dummy query as
// there are multiple types in the morph and we can't use single queries.
if (is_null($class = $this->$type)) {
return new MorphTo(
$this->newQuery(), $this, $id, null, $type, $name
);
}
// If we are not eager loading the relationship we will essentially treat this
// as a belongs-to style relationship since morph-to extends that class and
// we will pass in the appropriate values so that it behaves as expected.
else {
$class = $this->getActualClassNameForMorph($class);
$instance = new $class;
return new MorphTo(
$instance->newQuery(), $this, $id, $instance->getKeyName(), $type, $name
);
}
}
/**
* Define a many-to-many relationship.
*
* @param string $related
* @param string $collection
* @param string $foreignKey
* @param string $otherKey
* @param string $relation
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function belongsToMany($related, $collection = null, $foreignKey = null, $otherKey = null, $relation = null)
{
// If no relationship name was passed, we will pull backtraces to get the
// name of the calling function. We will use that function name as the
// title of this relation since that is a great convention to apply.
if (is_null($relation)) {
$relation = $this->getBelongsToManyCaller();
}
// Check if it is a relation with an original model.
if (! is_subclass_of($related, 'Jenssegers\Mongodb\Model')) {
return parent::belongsToMany($related, $collection, $foreignKey, $otherKey, $relation);
}
// First, we'll need to determine the foreign key and "other key" for the
// relationship. Once we have determined the keys we'll make the query
// instances as well as the relationship instances we need for this.
$foreignKey = $foreignKey ?: $this->getForeignKey() . 's';
$instance = new $related;
$otherKey = $otherKey ?: $instance->getForeignKey() . 's';
// If no table name was provided, we can guess it by concatenating the two
// models using underscores in alphabetical order. The two model names
// are transformed to snake case from their default CamelCase also.
if (is_null($collection)) {
$collection = $instance->getTable();
}
// Now we're ready to create a new query builder for the related model and
// the relationship instances for the relation. The relations will set
// appropriate query constraint and entirely manages the hydrations.
$query = $instance->newQuery();
return new BelongsToMany($query, $this, $collection, $foreignKey, $otherKey, $relation);
}
}
<?php namespace Jenssegers\Mongodb\Eloquent;
trait SoftDeletes
{
use \Illuminate\Database\Eloquent\SoftDeletes;
/**
* Get the fully qualified "deleted at" column.
*
* @return string
*/
public function getQualifiedDeletedAtColumn()
{
return $this->getDeletedAtColumn();
}
}
<?php namespace Jenssegers\Mongodb;
use Carbon\Carbon;
use DateTime;
use Illuminate\Database\Eloquent\Model as BaseModel;
use Illuminate\Database\Eloquent\Relations\Relation;
use Jenssegers\Mongodb\Eloquent\Builder;
use Jenssegers\Mongodb\Eloquent\HybridRelations;
use Jenssegers\Mongodb\Query\Builder as QueryBuilder;
use Jenssegers\Mongodb\Relations\EmbedsMany;
use Jenssegers\Mongodb\Relations\EmbedsOne;
use Jenssegers\Mongodb\Relations\EmbedsOneOrMany;
use MongoDate;
use MongoId;
use ReflectionMethod;
abstract class Model extends BaseModel
{
use HybridRelations;
/**
* The collection associated with the model.
*
* @var string
*/
protected $collection;
/**
* The primary key for the model.
*
* @var string
*/
protected $primaryKey = '_id';
/**
* The parent relation instance.
*
* @var Relation
*/
protected $parentRelation;
/**
* Custom accessor for the model's id.
*
* @param mixed $value
* @return mixed
*/
public function getIdAttribute($value)
{
// If we don't have a value for 'id', we will use the Mongo '_id' value.
// This allows us to work with models in a more sql-like way.
if (! $value and array_key_exists('_id', $this->attributes)) {
$value = $this->attributes['_id'];
}
// Convert MongoId's to string.
if ($value instanceof MongoId) {
return (string) $value;
}
return $value;
}
/**
* Get the table qualified key name.
*
* @return string
*/
public function getQualifiedKeyName()
{
return $this->getKeyName();
}
/**
* Define an embedded one-to-many relationship.
*
* @param string $related
* @param string $localKey
* @param string $foreignKey
* @param string $relation
* @return \Jenssegers\Mongodb\Relations\EmbedsMany
*/
protected function embedsMany($related, $localKey = null, $foreignKey = null, $relation = null)
{
// If no relation name was given, we will use this debug backtrace to extract
// the calling method's name and use that as the relationship name as most
// of the time this will be what we desire to use for the relatinoships.
if (is_null($relation)) {
list(, $caller) = debug_backtrace(false);
$relation = $caller['function'];
}
if (is_null($localKey)) {
$localKey = $relation;
}
if (is_null($foreignKey)) {
$foreignKey = snake_case(class_basename($this));
}
$query = $this->newQuery();
$instance = new $related;
return new EmbedsMany($query, $this, $instance, $localKey, $foreignKey, $relation);
}
/**
* Define an embedded one-to-many relationship.
*
* @param string $related
* @param string $localKey
* @param string $foreignKey
* @param string $relation
* @return \Jenssegers\Mongodb\Relations\EmbedsOne
*/
protected function embedsOne($related, $localKey = null, $foreignKey = null, $relation = null)
{
// If no relation name was given, we will use this debug backtrace to extract
// the calling method's name and use that as the relationship name as most
// of the time this will be what we desire to use for the relatinoships.
if (is_null($relation)) {
list(, $caller) = debug_backtrace(false);
$relation = $caller['function'];
}
if (is_null($localKey)) {
$localKey = $relation;
}
if (is_null($foreignKey)) {
$foreignKey = snake_case(class_basename($this));
}
$query = $this->newQuery();
$instance = new $related;
return new EmbedsOne($query, $this, $instance, $localKey, $foreignKey, $relation);
}
/**
* Convert a DateTime to a storable MongoDate object.
*
* @param DateTime|int $value
* @return MongoDate
*/
public function fromDateTime($value)
{
// If the value is already a MongoDate instance, we don't need to parse it.
if ($value instanceof MongoDate) {
return $value;
}
// Let Eloquent convert the value to a DateTime instance.
if (! $value instanceof DateTime) {
$value = parent::asDateTime($value);
}
return new MongoDate($value->getTimestamp());
}
/**
* Return a timestamp as DateTime object.
*
* @param mixed $value
* @return DateTime
*/
protected function asDateTime($value)
{
// Convert MongoDate instances.
if ($value instanceof MongoDate) {
return Carbon::createFromTimestamp($value->sec);
}
return parent::asDateTime($value);
}
/**
* Get the format for database stored dates.
*
* @return string
*/
protected function getDateFormat()
{
return $this->dateFormat ?: 'Y-m-d H:i:s';
}
/**
* Get a fresh timestamp for the model.
*
* @return MongoDate
*/
public function freshTimestamp()
{
return new MongoDate;
}
/**
* Get the table associated with the model.
*
* @return string
*/
public function getTable()
{
return $this->collection ?: parent::getTable();
}
/**
* Get an attribute from the model.
*
* @param string $key
* @return mixed
*/
public function getAttribute($key)
{
// Check if the key is an array dot notation.
if (str_contains($key, '.') and array_has($this->attributes, $key)) {
return $this->getAttributeValue($key);
}
$camelKey = camel_case($key);
// If the "attribute" exists as a method on the model, it may be an
// embedded model. If so, we need to return the result before it
// is handled by the parent method.
if (method_exists($this, $camelKey)) {
$method = new ReflectionMethod(get_called_class(), $camelKey);
// Ensure the method is not static to avoid conflicting with Eloquent methods.
if (! $method->isStatic()) {
$relations = $this->$camelKey();
// This attribute matches an embedsOne or embedsMany relation so we need
// to return the relation results instead of the interal attributes.
if ($relations instanceof EmbedsOneOrMany) {
// If the key already exists in the relationships array, it just means the
// relationship has already been loaded, so we'll just return it out of
// here because there is no need to query within the relations twice.
if (array_key_exists($key, $this->relations)) {
return $this->relations[$key];
}
// Get the relation results.
return $this->getRelationshipFromMethod($key, $camelKey);
}
}
}
return parent::getAttribute($key);
}
/**
* Get an attribute from the $attributes array.
*
* @param string $key
* @return mixed
*/
protected function getAttributeFromArray($key)
{
// Support keys in dot notation.
if (str_contains($key, '.')) {
$attributes = array_dot($this->attributes);
if (array_key_exists($key, $attributes)) {
return $attributes[$key];
}
}
return parent::getAttributeFromArray($key);
}
/**
* Set a given attribute on the model.
*
* @param string $key
* @param mixed $value
*/
public function setAttribute($key, $value)
{
// Convert _id to MongoId.
if ($key == '_id' and is_string($value)) {
$builder = $this->newBaseQueryBuilder();
$value = $builder->convertKey($value);
}
// Support keys in dot notation.
elseif (str_contains($key, '.')) {
if (in_array($key, $this->getDates()) && $value) {
$value = $this->fromDateTime($value);
}
array_set($this->attributes, $key, $value);
return;
}
parent::setAttribute($key, $value);
}
/**
* Get the casts array.
*
* @return array
*/
public function getCasts()
{
return $this->casts;
}
/**
* Convert the model's attributes to an array.
*
* @return array
*/
public function attributesToArray()
{
$attributes = parent::attributesToArray();
// Because the original Eloquent never returns objects, we convert
// MongoDB related objects to a string representation. This kind
// of mimics the SQL behaviour so that dates are formatted
// nicely when your models are converted to JSON.
foreach ($attributes as $key => &$value) {
if ($value instanceof MongoId) {
$value = (string) $value;
}
}
// Convert dot-notation dates.
foreach ($this->getDates() as $key) {
if (str_contains($key, '.') and array_has($attributes, $key)) {
array_set($attributes, $key, (string) $this->asDateTime(array_get($attributes, $key)));
}
}
return $attributes;
}
/**
* Determine if the new and old values for a given key are numerically equivalent.
*
* @param string $key
* @return bool
*/
protected function originalIsNumericallyEquivalent($key)
{
$current = $this->attributes[$key];
$original = $this->original[$key];
// Date comparison.
if (in_array($key, $this->getDates())) {
$current = $current instanceof MongoDate ? $this->asDateTime($current) : $current;
$original = $original instanceof MongoDate ? $this->asDateTime($original) : $original;
return $current == $original;
}
return parent::originalIsNumericallyEquivalent($key);
}
/**
* Remove one or more fields.
*
* @param mixed $columns
* @return int
*/
public function drop($columns)
{
if (! is_array($columns)) {
$columns = [$columns];
}
// Unset attributes
foreach ($columns as $column) {
$this->__unset($column);
}
// Perform unset only on current document
return $this->newQuery()->where($this->getKeyName(), $this->getKey())->unset($columns);
}
/**
* Append one or more values to an array.
*
* @return mixed
*/
public function push()
{
if ($parameters = func_get_args()) {
$unique = false;
if (count($parameters) == 3) {
list($column, $values, $unique) = $parameters;
} else {
list($column, $values) = $parameters;
}
// Do batch push by default.
if (! is_array($values)) {
$values = [$values];
}
$query = $this->setKeysForSaveQuery($this->newQuery());
$this->pushAttributeValues($column, $values, $unique);
return $query->push($column, $values, $unique);
}
return parent::push();
}
/**
* Remove one or more values from an array.
*
* @param string $column
* @param mixed $values
* @return mixed
*/
public function pull($column, $values)
{
// Do batch pull by default.
if (! is_array($values)) {
$values = [$values];
}
$query = $this->setKeysForSaveQuery($this->newQuery());
$this->pullAttributeValues($column, $values);
return $query->pull($column, $values);
}
/**
* Append one or more values to the underlying attribute value and sync with original.
*
* @param string $column
* @param array $values
* @param bool $unique
*/
protected function pushAttributeValues($column, array $values, $unique = false)
{
$current = $this->getAttributeFromArray($column) ?: [];
foreach ($values as $value) {
// Don't add duplicate values when we only want unique values.
if ($unique and in_array($value, $current)) {
continue;
}
array_push($current, $value);
}
$this->attributes[$column] = $current;
$this->syncOriginalAttribute($column);
}
/**
* Remove one or more values to the underlying attribute value and sync with original.
*
* @param string $column
* @param array $values
*/
protected function pullAttributeValues($column, array $values)
{
$current = $this->getAttributeFromArray($column) ?: [];
foreach ($values as $value) {
$keys = array_keys($current, $value);
foreach ($keys as $key) {
unset($current[$key]);
}
}
$this->attributes[$column] = array_values($current);
$this->syncOriginalAttribute($column);
}
/**
* Set the parent relation.
*
* @param \Illuminate\Database\Eloquent\Relations\Relation $relation
*/
public function setParentRelation(Relation $relation)
{
$this->parentRelation = $relation;
}
/**
* Get the parent relation.
*
* @return \Illuminate\Database\Eloquent\Relations\Relation
*/
public function getParentRelation()
{
return $this->parentRelation;
}
/**
* Create a new Eloquent query builder for the model.
*
* @param \Jenssegers\Mongodb\Query\Builder $query
* @return \Jenssegers\Mongodb\Eloquent\Builder|static
*/
public function newEloquentBuilder($query)
{
return new Builder($query);
}
/**
* Get a new query builder instance for the connection.
*
* @return Builder
*/
protected function newBaseQueryBuilder()
{
$connection = $this->getConnection();
return new QueryBuilder($connection, $connection->getPostProcessor());
}
/**
* Handle dynamic method calls into the method.
*
* @param string $method
* @param array $parameters
* @return mixed
*/
public function __call($method, $parameters)
{
// Unset method
if ($method == 'unset') {
return call_user_func_array([$this, 'drop'], $parameters);
}
return parent::__call($method, $parameters);
}
}
<?php namespace Jenssegers\Mongodb;
use Illuminate\Support\ServiceProvider;
class MongodbServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application events.
*/
public function boot()
{
Model::setConnectionResolver($this->app['db']);
Model::setEventDispatcher($this->app['events']);
}
/**
* Register the service provider.
*/
public function register()
{
$this->app->resolving('db', function ($db) {
$db->extend('mongodb', function ($config) {
return new Connection($config);
});
});
}
}
<?php namespace Jenssegers\Mongodb\Query;
use Closure;
use DateTime;
use Illuminate\Database\Query\Builder as BaseBuilder;
use Illuminate\Database\Query\Expression;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use Jenssegers\Mongodb\Connection;
use MongoDate;
use MongoId;
use MongoRegex;
class Builder extends BaseBuilder
{
/**
* The database collection.
*
* @var MongoCollection
*/
protected $collection;
/**
* The column projections.
*
* @var array
*/
public $projections;
/**
* The cursor timeout value.
*
* @var int
*/
public $timeout;
/**
* The cursor hint value.
*
* @var int
*/
public $hint;
/**
* Indicate if we are executing a pagination query.
*
* @var bool
*/
public $paginating = false;
/**
* All of the available clause operators.
*
* @var array
*/
protected $operators = [
'=', '<', '>', '<=', '>=', '<>', '!=',
'like', 'not like', 'between', 'ilike',
'&', '|', '^', '<<', '>>',
'rlike', 'regexp', 'not regexp',
'exists', 'type', 'mod', 'where', 'all', 'size', 'regex', 'text', 'slice', 'elemmatch',
'geowithin', 'geointersects', 'near', 'nearsphere', 'geometry',
'maxdistance', 'center', 'centersphere', 'box', 'polygon', 'uniquedocs',
];
/**
* Operator conversion.
*
* @var array
*/
protected $conversion = [
'=' => '=',
'!=' => '$ne',
'<>' => '$ne',
'<' => '$lt',
'<=' => '$lte',
'>' => '$gt',
'>=' => '$gte',
];
/**
* Create a new query builder instance.
*
* @param Connection $connection
*/
public function __construct(Connection $connection, Processor $processor)
{
$this->grammar = new Grammar;
$this->connection = $connection;
$this->processor = $processor;
}
/**
* Set the projections.
*
* @param array $columns
* @return $this
*/
public function project($columns)
{
$this->projections = is_array($columns) ? $columns : func_get_args();
return $this;
}
/**
* Set the cursor timeout in seconds.
*
* @param int $seconds
* @return $this
*/
public function timeout($seconds)
{
$this->timeout = $seconds;
return $this;
}
/**
* Set the cursor hint.
*
* @param mixed $index
* @return $this
*/
public function hint($index)
{
$this->hint = $index;
return $this;
}
/**
* Execute a query for a single record by ID.
*
* @param mixed $id
* @param array $columns
* @return mixed
*/
public function find($id, $columns = [])
{
return $this->where('_id', '=', $this->convertKey($id))->first($columns);
}
/**
* Execute the query as a "select" statement.
*
* @param array $columns
* @return array|static[]
*/
public function get($columns = [])
{
return $this->getFresh($columns);
}
/**
* Execute the query as a fresh "select" statement.
*
* @param array $columns
* @return array|static[]
*/
public function getFresh($columns = [])
{
// If no columns have been specified for the select statement, we will set them
// here to either the passed columns, or the standard default of retrieving
// all of the columns on the table using the "wildcard" column character.
if (is_null($this->columns)) {
$this->columns = $columns;
}
// Drop all columns if * is present, MongoDB does not work this way.
if (in_array('*', $this->columns)) {
$this->columns = [];
}
// Compile wheres
$wheres = $this->compileWheres();
// Use MongoDB's aggregation framework when using grouping or aggregation functions.
if ($this->groups or $this->aggregate or $this->paginating) {
$group = [];
// Add grouping columns to the $group part of the aggregation pipeline.
if ($this->groups) {
foreach ($this->groups as $column) {
$group['_id'][$column] = '$' . $column;
// When grouping, also add the $last operator to each grouped field,
// this mimics MySQL's behaviour a bit.
$group[$column] = ['$last' => '$' . $column];
}
// Do the same for other columns that are selected.
foreach ($this->columns as $column) {
$key = str_replace('.', '_', $column);
$group[$key] = ['$last' => '$' . $column];
}
}
// Add aggregation functions to the $group part of the aggregation pipeline,
// these may override previous aggregations.
if ($this->aggregate) {
$function = $this->aggregate['function'];
foreach ($this->aggregate['columns'] as $column) {
// Translate count into sum.
if ($function == 'count') {
$group['aggregate'] = ['$sum' => 1];
}
// Pass other functions directly.
else {
$group['aggregate'] = ['$' . $function => '$' . $column];
}
}
}
// When using pagination, we limit the number of returned columns
// by adding a projection.
if ($this->paginating) {
foreach ($this->columns as $column) {
$this->projections[$column] = 1;
}
}
// The _id field is mandatory when using grouping.
if ($group and empty($group['_id'])) {
$group['_id'] = null;
}
// Build the aggregation pipeline.
$pipeline = [];
if ($wheres) {
$pipeline[] = ['$match' => $wheres];
}
if ($group) {
$pipeline[] = ['$group' => $group];
}
// Apply order and limit
if ($this->orders) {
$pipeline[] = ['$sort' => $this->orders];
}
if ($this->offset) {
$pipeline[] = ['$skip' => $this->offset];
}
if ($this->limit) {
$pipeline[] = ['$limit' => $this->limit];
}
if ($this->projections) {
$pipeline[] = ['$project' => $this->projections];
}
// Execute aggregation
$results = $this->collection->aggregate($pipeline);
// Return results
return $results['result'];
}
// Distinct query
elseif ($this->distinct) {
// Return distinct results directly
$column = isset($this->columns[0]) ? $this->columns[0] : '_id';
// Execute distinct
if ($wheres) {
$result = $this->collection->distinct($column, $wheres);
} else {
$result = $this->collection->distinct($column);
}
return $result;
}
// Normal query
else {
$columns = [];
// Convert select columns to simple projections.
foreach ($this->columns as $column) {
$columns[$column] = true;
}
// Add custom projections.
if ($this->projections) {
$columns = array_merge($columns, $this->projections);
}
// Execute query and get MongoCursor
$cursor = $this->collection->find($wheres, $columns);
// Apply order, offset, limit and hint
if ($this->timeout) {
$cursor->timeout($this->timeout);
}
if ($this->orders) {
$cursor->sort($this->orders);
}
if ($this->offset) {
$cursor->skip($this->offset);
}
if ($this->limit) {
$cursor->limit($this->limit);
}
if ($this->hint) {
$cursor->hint($this->hint);
}
// Return results as an array with numeric keys
return iterator_to_array($cursor, false);
}
}
/**
* Generate the unique cache key for the current query.
*
* @return string
*/
public function generateCacheKey()
{
$key = [
'connection' => $this->connection->getName(),
'collection' => $this->collection->getName(),
'wheres' => $this->wheres,
'columns' => $this->columns,
'groups' => $this->groups,
'orders' => $this->orders,
'offset' => $this->offset,
'limit' => $this->limit,
'aggregate' => $this->aggregate,
];
return md5(serialize(array_values($key)));
}
/**
* Execute an aggregate function on the database.
*
* @param string $function
* @param array $columns
* @return mixed
*/
public function aggregate($function, $columns = [])
{
$this->aggregate = compact('function', 'columns');
$results = $this->get($columns);
// Once we have executed the query, we will reset the aggregate property so
// that more select queries can be executed against the database without
// the aggregate value getting in the way when the grammar builds it.
$this->columns = null;
$this->aggregate = null;
if (isset($results[0])) {
$result = (array) $results[0];
return $result['aggregate'];
}
}
/**
* Determine if any rows exist for the current query.
*
* @return bool
*/
public function exists()
{
return ! is_null($this->first());
}
/**
* Force the query to only return distinct results.
*
* @return Builder
*/
public function distinct($column = false)
{
$this->distinct = true;
if ($column) {
$this->columns = [$column];
}
return $this;
}
/**
* Add an "order by" clause to the query.
*
* @param string $column
* @param string $direction
* @return Builder
*/
public function orderBy($column, $direction = 'asc')
{
if (is_string($direction)) {
$direction = (strtolower($direction) == 'asc' ? 1 : -1);
}
if ($column == 'natural') {
$this->orders['$natural'] = $direction;
} else {
$this->orders[$column] = $direction;
}
return $this;
}
/**
* Add a where between statement to the query.
*
* @param string $column
* @param array $values
* @param string $boolean
* @param bool $not
* @return Builder
*/
public function whereBetween($column, array $values, $boolean = 'and', $not = false)
{
$type = 'between';
$this->wheres[] = compact('column', 'type', 'boolean', 'values', 'not');
return $this;
}
/**
* Set the limit and offset for a given page.
*
* @param int $page
* @param int $perPage
* @return \Illuminate\Database\Query\Builder|static
*/
public function forPage($page, $perPage = 15)
{
$this->paginating = true;
return $this->skip(($page - 1) * $perPage)->take($perPage);
}
/**
* Insert a new record into the database.
*
* @param array $values
* @return bool
*/
public function insert(array $values)
{
// Since every insert gets treated like a batch insert, we will have to detect
// if the user is inserting a single document or an array of documents.
$batch = true;
foreach ($values as $value) {
// As soon as we find a value that is not an array we assume the user is
// inserting a single document.
if (! is_array($value)) {
$batch = false;
break;
}
}
if (! $batch) {
$values = [$values];
}
// Batch insert
$result = $this->collection->batchInsert($values);
return (1 == (int) $result['ok']);
}
/**
* Insert a new record and get the value of the primary key.
*
* @param array $values
* @param string $sequence
* @return int
*/
public function insertGetId(array $values, $sequence = null)
{
$result = $this->collection->insert($values);
if (1 == (int) $result['ok']) {
if (is_null($sequence)) {
$sequence = '_id';
}
// Return id
return $values[$sequence];
}
}
/**
* Update a record in the database.
*
* @param array $values
* @param array $options
* @return int
*/
public function update(array $values, array $options = [])
{
// Use $set as default operator.
if (! starts_with(key($values), '$')) {
$values = ['$set' => $values];
}
return $this->performUpdate($values, $options);
}
/**
* Increment a column's value by a given amount.
*
* @param string $column
* @param int $amount
* @param array $extra
* @return int
*/
public function increment($column, $amount = 1, array $extra = [], array $options = [])
{
$query = ['$inc' => [$column => $amount]];
if (! empty($extra)) {
$query['$set'] = $extra;
}
// Protect
$this->where(function ($query) use ($column) {
$query->where($column, 'exists', false);
$query->orWhereNotNull($column);
});
return $this->performUpdate($query, $options);
}
/**
* Decrement a column's value by a given amount.
*
* @param string $column
* @param int $amount
* @param array $extra
* @return int
*/
public function decrement($column, $amount = 1, array $extra = [], array $options = [])
{
return $this->increment($column, -1 * $amount, $extra, $options);
}
/**
* Get an array with the values of a given column.
*
* @param string $column
* @param string|null $key
* @return array
*/
public function pluck($column, $key = null)
{
$results = $this->get(is_null($key) ? [$column] : [$column, $key]);
// If the columns are qualified with a table or have an alias, we cannot use
// those directly in the "pluck" operations since the results from the DB
// are only keyed by the column itself. We'll strip the table out here.
return Arr::pluck(
$results,
$column,
$key
);
}
/**
* Delete a record from the database.
*
* @param mixed $id
* @return int
*/
public function delete($id = null)
{
$wheres = $this->compileWheres();
$result = $this->collection->remove($wheres);
if (1 == (int) $result['ok']) {
return $result['n'];
}
return 0;
}
/**
* Set the collection which the query is targeting.
*
* @param string $collection
* @return Builder
*/
public function from($collection)
{
if ($collection) {
$this->collection = $this->connection->getCollection($collection);
}
return parent::from($collection);
}
/**
* Run a truncate statement on the table.
*/
public function truncate()
{
$result = $this->collection->remove();
return (1 == (int) $result['ok']);
}
/**
* Get an array with the values of a given column.
*
* @param string $column
* @param string $key
* @return array
*/
public function lists($column, $key = null)
{
if ($key == '_id') {
$results = new Collection($this->get([$column, $key]));
// Convert MongoId's to strings so that lists can do its work.
$results = $results->map(function ($item) {
$item['_id'] = (string) $item['_id'];
return $item;
});
return $results->lists($column, $key)->all();
}
return parent::lists($column, $key);
}
/**
* Create a raw database expression.
*
* @param closure $expression
* @return mixed
*/
public function raw($expression = null)
{
// Execute the closure on the mongodb collection
if ($expression instanceof Closure) {
return call_user_func($expression, $this->collection);
}
// Create an expression for the given value
elseif (! is_null($expression)) {
return new Expression($expression);
}
// Quick access to the mongodb collection
return $this->collection;
}
/**
* Append one or more values to an array.
*
* @param mixed $column
* @param mixed $value
* @return int
*/
public function push($column, $value = null, $unique = false)
{
// Use the addToSet operator in case we only want unique items.
$operator = $unique ? '$addToSet' : '$push';
// Check if we are pushing multiple values.
$batch = (is_array($value) and array_keys($value) === range(0, count($value) - 1));
if (is_array($column)) {
$query = [$operator => $column];
} elseif ($batch) {
$query = [$operator => [$column => ['$each' => $value]]];
} else {
$query = [$operator => [$column => $value]];
}
return $this->performUpdate($query);
}
/**
* Remove one or more values from an array.
*
* @param mixed $column
* @param mixed $value
* @return int
*/
public function pull($column, $value = null)
{
// Check if we passed an associative array.
$batch = (is_array($value) and array_keys($value) === range(0, count($value) - 1));
// If we are pulling multiple values, we need to use $pullAll.
$operator = $batch ? '$pullAll' : '$pull';
if (is_array($column)) {
$query = [$operator => $column];
} else {
$query = [$operator => [$column => $value]];
}
return $this->performUpdate($query);
}
/**
* Remove one or more fields.
*
* @param mixed $columns
* @return int
*/
public function drop($columns)
{
if (! is_array($columns)) {
$columns = [$columns];
}
$fields = [];
foreach ($columns as $column) {
$fields[$column] = 1;
}
$query = ['$unset' => $fields];
return $this->performUpdate($query);
}
/**
* Get a new instance of the query builder.
*
* @return Builder
*/
public function newQuery()
{
return new Builder($this->connection, $this->processor);
}
/**
* Perform an update query.
*
* @param array $query
* @param array $options
* @return int
*/
protected function performUpdate($query, array $options = [])
{
// Update multiple items by default.
if (! array_key_exists('multiple', $options)) {
$options['multiple'] = true;
}
$wheres = $this->compileWheres();
$result = $this->collection->update($wheres, $query, $options);
if (1 == (int) $result['ok']) {
return $result['n'];
}
return 0;
}
/**
* Convert a key to MongoID if needed.
*
* @param mixed $id
* @return mixed
*/
public function convertKey($id)
{
if (MongoId::isValid($id)) {
return new MongoId($id);
}
return $id;
}
/**
* Add a basic where clause to the query.
*
* @param string $column
* @param string $operator
* @param mixed $value
* @param string $boolean
* @return \Illuminate\Database\Query\Builder|static
*
* @throws \InvalidArgumentException
*/
public function where($column, $operator = null, $value = null, $boolean = 'and')
{
$params = func_get_args();
// Remove the leading $ from operators.
if (func_num_args() == 3) {
$operator = &$params[1];
if (starts_with($operator, '$')) {
$operator = substr($operator, 1);
}
}
return call_user_func_array('parent::where', $params);
}
/**
* Compile the where array.
*
* @return array
*/
protected function compileWheres()
{
// The wheres to compile.
$wheres = $this->wheres ?: [];
// We will add all compiled wheres to this array.
$compiled = [];
foreach ($wheres as $i => &$where) {
// Make sure the operator is in lowercase.
if (isset($where['operator'])) {
$where['operator'] = strtolower($where['operator']);
// Operator conversions
$convert = [
'regexp' => 'regex',
'elemmatch' => 'elemMatch',
'geointersects' => 'geoIntersects',
'geowithin' => 'geoWithin',
'nearsphere' => 'nearSphere',
'maxdistance' => 'maxDistance',
'centersphere' => 'centerSphere',
'uniquedocs' => 'uniqueDocs',
];
if (array_key_exists($where['operator'], $convert)) {
$where['operator'] = $convert[$where['operator']];
}
}
// Convert id's.
if (isset($where['column']) and ($where['column'] == '_id' or ends_with($where['column'], '._id'))) {
// Multiple values.
if (isset($where['values'])) {
foreach ($where['values'] as &$value) {
$value = $this->convertKey($value);
}
}
// Single value.
elseif (isset($where['value'])) {
$where['value'] = $this->convertKey($where['value']);
}
}
// Convert DateTime values to MongoDate.
if (isset($where['value']) and $where['value'] instanceof DateTime) {
$where['value'] = new MongoDate($where['value']->getTimestamp());
}
// The next item in a "chain" of wheres devices the boolean of the
// first item. So if we see that there are multiple wheres, we will
// use the operator of the next where.
if ($i == 0 and count($wheres) > 1 and $where['boolean'] == 'and') {
$where['boolean'] = $wheres[$i + 1]['boolean'];
}
// We use different methods to compile different wheres.
$method = "compileWhere{$where['type']}";
$result = $this->{$method}($where);
// Wrap the where with an $or operator.
if ($where['boolean'] == 'or') {
$result = ['$or' => [$result]];
}
// If there are multiple wheres, we will wrap it with $and. This is needed
// to make nested wheres work.
elseif (count($wheres) > 1) {
$result = ['$and' => [$result]];
}
// Merge the compiled where with the others.
$compiled = array_merge_recursive($compiled, $result);
}
return $compiled;
}
protected function compileWhereBasic($where)
{
extract($where);
// Replace like with a MongoRegex instance.
if ($operator == 'like') {
$operator = '=';
// Convert to regular expression.
$regex = preg_replace('#(^|[^\\\])%#', '$1.*', preg_quote($value));
// Convert like to regular expression.
if (! starts_with($value, '%')) {
$regex = '^' . $regex;
}
if (! ends_with($value, '%')) {
$regex = $regex . '$';
}
$value = new MongoRegex("/$regex/i");
}
// Manipulate regexp operations.
elseif (in_array($operator, ['regexp', 'not regexp', 'regex', 'not regex'])) {
// Automatically convert regular expression strings to MongoRegex objects.
if (! $value instanceof MongoRegex) {
$value = new MongoRegex($value);
}
// For inverse regexp operations, we can just use the $not operator
// and pass it a MongoRegex instence.
if (starts_with($operator, 'not')) {
$operator = 'not';
}
}
if (! isset($operator) or $operator == '=') {
$query = [$column => $value];
} elseif (array_key_exists($operator, $this->conversion)) {
$query = [$column => [$this->conversion[$operator] => $value]];
} else {
$query = [$column => ['$' . $operator => $value]];
}
return $query;
}
protected function compileWhereNested($where)
{
extract($where);
return $query->compileWheres();
}
protected function compileWhereIn($where)
{
extract($where);
return [$column => ['$in' => array_values($values)]];
}
protected function compileWhereNotIn($where)
{
extract($where);
return [$column => ['$nin' => array_values($values)]];
}
protected function compileWhereNull($where)
{
$where['operator'] = '=';
$where['value'] = null;
return $this->compileWhereBasic($where);
}
protected function compileWhereNotNull($where)
{
$where['operator'] = '!=';
$where['value'] = null;
return $this->compileWhereBasic($where);
}
protected function compileWhereBetween($where)
{
extract($where);
if ($not) {
return [
'$or' => [
[
$column => [
'$lte' => $values[0],
],
],
[
$column => [
'$gte' => $values[1],
],
],
],
];
} else {
return [
$column => [
'$gte' => $values[0],
'$lte' => $values[1],
],
];
}
}
protected function compileWhereRaw($where)
{
return $where['sql'];
}
/**
* Handle dynamic method calls into the method.
*
* @param string $method
* @param array $parameters
* @return mixed
*/
public function __call($method, $parameters)
{
if ($method == 'unset') {
return call_user_func_array([$this, 'drop'], $parameters);
}
return parent::__call($method, $parameters);
}
}
<?php namespace Jenssegers\Mongodb\Query;
use Illuminate\Database\Query\Grammars\Grammar as BaseGrammar;
class Grammar extends BaseGrammar
{
}
<?php namespace Jenssegers\Mongodb\Query;
use Illuminate\Database\Query\Processors\Processor as BaseProcessor;
class Processor extends BaseProcessor
{
}
<?php namespace Jenssegers\Mongodb\Relations;
class BelongsTo extends \Illuminate\Database\Eloquent\Relations\BelongsTo
{
/**
* Set the base constraints on the relation query.
*/
public function addConstraints()
{
if (static::$constraints) {
// For belongs to relationships, which are essentially the inverse of has one
// or has many relationships, we need to actually query on the primary key
// of the related models matching on the foreign key that's on a parent.
$this->query->where($this->otherKey, '=', $this->parent->{$this->foreignKey});
}
}
/**
* Set the constraints for an eager load of the relation.
*
* @param array $models
*/
public function addEagerConstraints(array $models)
{
// We'll grab the primary key name of the related models since it could be set to
// a non-standard name and not "id". We will then construct the constraint for
// our eagerly loading query so it returns the proper models from execution.
$key = $this->otherKey;
$this->query->whereIn($key, $this->getEagerModelKeys($models));
}
}
<?php namespace Jenssegers\Mongodb\Relations;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany as EloquentBelongsToMany;
class BelongsToMany extends EloquentBelongsToMany
{
/**
* Hydrate the pivot table relationship on the models.
*
* @param array $models
*/
protected function hydratePivotRelation(array $models)
{
// Do nothing.
}
/**
* Set the select clause for the relation query.
*
* @param array $columns
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
protected function getSelectColumns(array $columns = ['*'])
{
return $columns;
}
/**
* Set the base constraints on the relation query.
*/
public function addConstraints()
{
if (static::$constraints) {
$this->setWhere();
}
}
/**
* Set the where clause for the relation query.
*
* @return $this
*/
protected function setWhere()
{
$foreign = $this->getForeignKey();
$this->query->where($foreign, '=', $this->parent->getKey());
return $this;
}
/**
* Save a new model and attach it to the parent model.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @param array $joining
* @param bool $touch
* @return \Illuminate\Database\Eloquent\Model
*/
public function save(Model $model, array $joining = [], $touch = true)
{
$model->save(['touch' => false]);
$this->attach($model, $joining, $touch);
return $model;
}
/**
* Create a new instance of the related model.
*
* @param array $attributes
* @param array $joining
* @param bool $touch
* @return \Illuminate\Database\Eloquent\Model
*/
public function create(array $attributes, array $joining = [], $touch = true)
{
$instance = $this->related->newInstance($attributes);
// Once we save the related model, we need to attach it to the base model via
// through intermediate table so we'll use the existing "attach" method to
// accomplish this which will insert the record and any more attributes.
$instance->save(['touch' => false]);
$this->attach($instance, $joining, $touch);
return $instance;
}
/**
* Sync the intermediate tables with a list of IDs or collection of models.
*
* @param array $ids
* @param bool $detaching
* @return array
*/
public function sync($ids, $detaching = true)
{
$changes = [
'attached' => [], 'detached' => [], 'updated' => [],
];
if ($ids instanceof Collection) {
$ids = $ids->modelKeys();
}
// First we need to attach any of the associated models that are not currently
// in this joining table. We'll spin through the given IDs, checking to see
// if they exist in the array of current ones, and if not we will insert.
$current = $this->parent->{$this->otherKey} ?: [];
// See issue #256.
if ($current instanceof Collection) {
$current = $ids->modelKeys();
}
$records = $this->formatSyncList($ids);
$detach = array_diff($current, array_keys($records));
// We need to make sure we pass a clean array, so that it is not interpreted
// as an associative array.
$detach = array_values($detach);
// Next, we will take the differences of the currents and given IDs and detach
// all of the entities that exist in the "current" array but are not in the
// the array of the IDs given to the method which will complete the sync.
if ($detaching and count($detach) > 0) {
$this->detach($detach);
$changes['detached'] = (array) array_map(function ($v) {
return is_numeric($v) ? (int) $v : (string) $v;
}, $detach);
}
// Now we are finally ready to attach the new records. Note that we'll disable
// touching until after the entire operation is complete so we don't fire a
// ton of touch operations until we are totally done syncing the records.
$changes = array_merge(
$changes, $this->attachNew($records, $current, false)
);
if (count($changes['attached']) || count($changes['updated'])) {
$this->touchIfTouching();
}
return $changes;
}
/**
* Update an existing pivot record on the table.
*
* @param mixed $id
* @param array $attributes
* @param bool $touch
*/
public function updateExistingPivot($id, array $attributes, $touch = true)
{
// Do nothing, we have no pivot table.
}
/**
* Attach a model to the parent.
*
* @param mixed $id
* @param array $attributes
* @param bool $touch
*/
public function attach($id, array $attributes = [], $touch = true)
{
if ($id instanceof Model) {
$model = $id;
$id = $model->getKey();
// Attach the new parent id to the related model.
$model->push($this->foreignKey, $this->parent->getKey(), true);
} else {
$query = $this->newRelatedQuery();
$query->whereIn($this->related->getKeyName(), (array) $id);
// Attach the new parent id to the related model.
$query->push($this->foreignKey, $this->parent->getKey(), true);
}
// Attach the new ids to the parent model.
$this->parent->push($this->otherKey, (array) $id, true);
if ($touch) {
$this->touchIfTouching();
}
}
/**
* Detach models from the relationship.
*
* @param int|array $ids
* @param bool $touch
* @return int
*/
public function detach($ids = [], $touch = true)
{
if ($ids instanceof Model) {
$ids = (array) $ids->getKey();
}
$query = $this->newRelatedQuery();
// If associated IDs were passed to the method we will only delete those
// associations, otherwise all of the association ties will be broken.
// We'll return the numbers of affected rows when we do the deletes.
$ids = (array) $ids;
// Detach all ids from the parent model.
$this->parent->pull($this->otherKey, $ids);
// Prepare the query to select all related objects.
if (count($ids) > 0) {
$query->whereIn($this->related->getKeyName(), $ids);
}
// Remove the relation to the parent.
$query->pull($this->foreignKey, $this->parent->getKey());
if ($touch) {
$this->touchIfTouching();
}
return count($ids);
}
/**
* Build model dictionary keyed by the relation's foreign key.
*
* @param \Illuminate\Database\Eloquent\Collection $results
* @return array
*/
protected function buildDictionary(Collection $results)
{
$foreign = $this->foreignKey;
// First we will build a dictionary of child models keyed by the foreign key
// of the relation so that we will easily and quickly match them to their
// parents without having a possibly slow inner loops for every models.
$dictionary = [];
foreach ($results as $result) {
foreach ($result->$foreign as $item) {
$dictionary[$item][] = $result;
}
}
return $dictionary;
}
/**
* Create a new query builder for the related model.
*
* @return \Illuminate\Database\Query\Builder
*/
protected function newPivotQuery()
{
return $this->newRelatedQuery();
}
/**
* Create a new query builder for the related model.
*
* @return \Illuminate\Database\Query\Builder
*/
public function newRelatedQuery()
{
return $this->related->newQuery();
}
/**
* Get the fully qualified foreign key for the relation.
*
* @return string
*/
public function getForeignKey()
{
return $this->foreignKey;
}
}
<?php namespace Jenssegers\Mongodb\Relations;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Pagination\Paginator;
use MongoId;
class EmbedsMany extends EmbedsOneOrMany
{
/**
* Get the results of the relationship.
*
* @return \Illuminate\Database\Eloquent\Collection
*/
public function getResults()
{
return $this->toCollection($this->getEmbedded());
}
/**
* Save a new model and attach it to the parent model.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @return \Illuminate\Database\Eloquent\Model
*/
public function performInsert(Model $model)
{
// Generate a new key if needed.
if ($model->getKeyName() == '_id' and ! $model->getKey()) {
$model->setAttribute('_id', new MongoId);
}
// For deeply nested documents, let the parent handle the changes.
if ($this->isNested()) {
$this->associate($model);
return $this->parent->save();
}
// Push the new model to the database.
$result = $this->getBaseQuery()->push($this->localKey, $model->getAttributes(), true);
// Attach the model to its parent.
if ($result) {
$this->associate($model);
}
return $result ? $model : false;
}
/**
* Save an existing model and attach it to the parent model.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @return Model|bool
*/
public function performUpdate(Model $model)
{
// For deeply nested documents, let the parent handle the changes.
if ($this->isNested()) {
$this->associate($model);
return $this->parent->save();
}
// Get the correct foreign key value.
$foreignKey = $this->getForeignKeyValue($model);
// Use array dot notation for better update behavior.
$values = array_dot($model->getDirty(), $this->localKey . '.$.');
// Update document in database.
$result = $this->getBaseQuery()->where($this->localKey . '.' . $model->getKeyName(), $foreignKey)
->update($values);
// Attach the model to its parent.
if ($result) {
$this->associate($model);
}
return $result ? $model : false;
}
/**
* Delete an existing model and detach it from the parent model.
*
* @param Model $model
* @return int
*/
public function performDelete(Model $model)
{
// For deeply nested documents, let the parent handle the changes.
if ($this->isNested()) {
$this->dissociate($model);
return $this->parent->save();
}
// Get the correct foreign key value.
$foreignKey = $this->getForeignKeyValue($model);
$result = $this->getBaseQuery()->pull($this->localKey, [$model->getKeyName() => $foreignKey]);
if ($result) {
$this->dissociate($model);
}
return $result;
}
/**
* Associate the model instance to the given parent, without saving it to the database.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @return \Illuminate\Database\Eloquent\Model
*/
public function associate(Model $model)
{
if (! $this->contains($model)) {
return $this->associateNew($model);
} else {
return $this->associateExisting($model);
}
}
/**
* Dissociate the model instance from the given parent, without saving it to the database.
*
* @param mixed $ids
* @return int
*/
public function dissociate($ids = [])
{
$ids = $this->getIdsArrayFrom($ids);
$records = $this->getEmbedded();
$primaryKey = $this->related->getKeyName();
// Remove the document from the parent model.
foreach ($records as $i => $record) {
if (in_array($record[$primaryKey], $ids)) {
unset($records[$i]);
}
}
$this->setEmbedded($records);
// We return the total number of deletes for the operation. The developers
// can then check this number as a boolean type value or get this total count
// of records deleted for logging, etc.
return count($ids);
}
/**
* Destroy the embedded models for the given IDs.
*
* @param mixed $ids
* @return int
*/
public function destroy($ids = [])
{
$count = 0;
$ids = $this->getIdsArrayFrom($ids);
// Get all models matching the given ids.
$models = $this->getResults()->only($ids);
// Pull the documents from the database.
foreach ($models as $model) {
if ($model->delete()) {
$count++;
}
}
return $count;
}
/**
* Delete all embedded models.
*
* @return int
*/
public function delete()
{
// Overwrite the local key with an empty array.
$result = $this->query->update([$this->localKey => []]);
if ($result) {
$this->setEmbedded([]);
}
return $result;
}
/**
* Destroy alias.
*
* @param mixed $ids
* @return int
*/
public function detach($ids = [])
{
return $this->destroy($ids);
}
/**
* Save alias.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @return \Illuminate\Database\Eloquent\Model
*/
public function attach(Model $model)
{
return $this->save($model);
}
/**
* Associate a new model instance to the given parent, without saving it to the database.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @return \Illuminate\Database\Eloquent\Model
*/
protected function associateNew($model)
{
// Create a new key if needed.
if (! $model->getAttribute('_id')) {
$model->setAttribute('_id', new MongoId);
}
$records = $this->getEmbedded();
// Add the new model to the embedded documents.
$records[] = $model->getAttributes();
return $this->setEmbedded($records);
}
/**
* Associate an existing model instance to the given parent, without saving it to the database.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @return \Illuminate\Database\Eloquent\Model
*/
protected function associateExisting($model)
{
// Get existing embedded documents.
$records = $this->getEmbedded();
$primaryKey = $this->related->getKeyName();
$key = $model->getKey();
// Replace the document in the parent model.
foreach ($records as &$record) {
if ($record[$primaryKey] == $key) {
$record = $model->getAttributes();
break;
}
}
return $this->setEmbedded($records);
}
/**
* Get a paginator for the "select" statement.
*
* @param int $perPage
* @return \Illuminate\Pagination\Paginator
*/
public function paginate($perPage = null)
{
$page = Paginator::resolveCurrentPage();
$perPage = $perPage ?: $this->related->getPerPage();
$results = $this->getEmbedded();
$total = count($results);
$start = ($page - 1) * $perPage;
$sliced = array_slice($results, $start, $perPage);
return new LengthAwarePaginator($sliced, $total, $perPage, $page, [
'path' => Paginator::resolveCurrentPath(),
]);
}
/**
* Get the embedded records array.
*
* @return array
*/
protected function getEmbedded()
{
return parent::getEmbedded() ?: [];
}
/**
* Set the embedded records array.
*
* @param array $models
*/
protected function setEmbedded($models)
{
if (! is_array($models)) {
$models = [$models];
}
return parent::setEmbedded(array_values($models));
}
/**
* Handle dynamic method calls to the relationship.
*
* @param string $method
* @param array $parameters
* @return mixed
*/
public function __call($method, $parameters)
{
// Collection methods
if (method_exists('Illuminate\Database\Eloquent\Collection', $method)) {
return call_user_func_array([$this->getResults(), $method], $parameters);
}
return parent::__call($method, $parameters);
}
}
<?php namespace Jenssegers\Mongodb\Relations;
use Illuminate\Database\Eloquent\Model;
use MongoId;
class EmbedsOne extends EmbedsOneOrMany
{
/**
* Get the results of the relationship.
*
* @return \Illuminate\Database\Eloquent\Model
*/
public function getResults()
{
return $this->toModel($this->getEmbedded());
}
/**
* Save a new model and attach it to the parent model.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @return \Illuminate\Database\Eloquent\Model
*/
public function performInsert(Model $model)
{
// Generate a new key if needed.
if ($model->getKeyName() == '_id' and ! $model->getKey()) {
$model->setAttribute('_id', new MongoId);
}
// For deeply nested documents, let the parent handle the changes.
if ($this->isNested()) {
$this->associate($model);
return $this->parent->save();
}
$result = $this->getBaseQuery()->update([$this->localKey => $model->getAttributes()]);
// Attach the model to its parent.
if ($result) {
$this->associate($model);
}
return $result ? $model : false;
}
/**
* Save an existing model and attach it to the parent model.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @return \Illuminate\Database\Eloquent\Model|bool
*/
public function performUpdate(Model $model)
{
if ($this->isNested()) {
$this->associate($model);
return $this->parent->save();
}
// Use array dot notation for better update behavior.
$values = array_dot($model->getDirty(), $this->localKey . '.');
$result = $this->getBaseQuery()->update($values);
// Attach the model to its parent.
if ($result) {
$this->associate($model);
}
return $result ? $model : false;
}
/**
* Delete an existing model and detach it from the parent model.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @return int
*/
public function performDelete(Model $model)
{
// For deeply nested documents, let the parent handle the changes.
if ($this->isNested()) {
$this->dissociate($model);
return $this->parent->save();
}
// Overwrite the local key with an empty array.
$result = $this->getBaseQuery()->update([$this->localKey => null]);
// Detach the model from its parent.
if ($result) {
$this->dissociate();
}
return $result;
}
/**
* Attach the model to its parent.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @return \Illuminate\Database\Eloquent\Model
*/
public function associate(Model $model)
{
return $this->setEmbedded($model->getAttributes());
}
/**
* Detach the model from its parent.
*
* @return \Illuminate\Database\Eloquent\Model
*/
public function dissociate()
{
return $this->setEmbedded(null);
}
/**
* Delete all embedded models.
*
* @return int
*/
public function delete()
{
$model = $this->getResults();
return $this->performDelete($model);
}
}
<?php namespace Jenssegers\Mongodb\Relations;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\Relation;
abstract class EmbedsOneOrMany extends Relation
{
/**
* The local key of the parent model.
*
* @var string
*/
protected $localKey;
/**
* The foreign key of the parent model.
*
* @var string
*/
protected $foreignKey;
/**
* The "name" of the relationship.
*
* @var string
*/
protected $relation;
/**
* Create a new embeds many relationship instance.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param \Illuminate\Database\Eloquent\Model $parent
* @param \Illuminate\Database\Eloquent\Model $related
* @param string $localKey
* @param string $foreignKey
* @param string $relation
*/
public function __construct(Builder $query, Model $parent, Model $related, $localKey, $foreignKey, $relation)
{
$this->query = $query;
$this->parent = $parent;
$this->related = $related;
$this->localKey = $localKey;
$this->foreignKey = $foreignKey;
$this->relation = $relation;
// If this is a nested relation, we need to get the parent query instead.
if ($parentRelation = $this->getParentRelation()) {
$this->query = $parentRelation->getQuery();
}
$this->addConstraints();
}
/**
* Set the base constraints on the relation query.
*/
public function addConstraints()
{
if (static::$constraints) {
$this->query->where($this->getQualifiedParentKeyName(), '=', $this->getParentKey());
}
}
/**
* Set the constraints for an eager load of the relation.
*
* @param array $models
*/
public function addEagerConstraints(array $models)
{
// There are no eager loading constraints.
}
/**
* Initialize the relation on a set of models.
*
* @param array $models
* @param string $relation
*/
public function initRelation(array $models, $relation)
{
foreach ($models as $model) {
$model->setParentRelation($this);
$model->setRelation($relation, $this->related->newCollection());
}
return $models;
}
/**
* Match the eagerly loaded results to their parents.
*
* @param array $models
* @param \Illuminate\Database\Eloquent\Collection $results
* @param string $relation
* @return array
*/
public function match(array $models, Collection $results, $relation)
{
foreach ($models as $model) {
$results = $model->$relation()->getResults();
$model->setParentRelation($this);
$model->setRelation($relation, $results);
}
return $models;
}
/**
* Shorthand to get the results of the relationship.
*
* @return \Illuminate\Database\Eloquent\Collection
*/
public function get()
{
return $this->getResults();
}
/**
* Get the number of embedded models.
*
* @return int
*/
public function count()
{
return count($this->getEmbedded());
}
/**
* Attach a model instance to the parent model.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @return \Illuminate\Database\Eloquent\Model
*/
public function save(Model $model)
{
$model->setParentRelation($this);
return $model->save() ? $model : false;
}
/**
* Attach a collection of models to the parent instance.
*
* @param \Illuminate\Database\Eloquent\Collection|array $models
* @return \Illuminate\Database\Eloquent\Collection|array
*/
public function saveMany($models)
{
foreach ($models as $model) {
$this->save($model);
}
return $models;
}
/**
* Create a new instance of the related model.
*
* @param array $attributes
* @return \Illuminate\Database\Eloquent\Model
*/
public function create(array $attributes)
{
// Here we will set the raw attributes to avoid hitting the "fill" method so
// that we do not have to worry about a mass accessor rules blocking sets
// on the models. Otherwise, some of these attributes will not get set.
$instance = $this->related->newInstance($attributes);
$instance->setParentRelation($this);
$instance->save();
return $instance;
}
/**
* Create an array of new instances of the related model.
*
* @param array $records
* @return array
*/
public function createMany(array $records)
{
$instances = [];
foreach ($records as $record) {
$instances[] = $this->create($record);
}
return $instances;
}
/**
* Transform single ID, single Model or array of Models into an array of IDs.
*
* @param mixed $ids
* @return array
*/
protected function getIdsArrayFrom($ids)
{
if ($ids instanceof \Illuminate\Support\Collection) {
$ids = $ids->all();
}
if (! is_array($ids)) {
$ids = [$ids];
}
foreach ($ids as &$id) {
if ($id instanceof Model) {
$id = $id->getKey();
}
}
return $ids;
}
/**
* Get the embedded records array.
*
* @return array
*/
protected function getEmbedded()
{
// Get raw attributes to skip relations and accessors.
$attributes = $this->parent->getAttributes();
$embedded = isset($attributes[$this->localKey]) ? (array) $attributes[$this->localKey] : [];
return $embedded;
}
/**
* Set the embedded records array.
*
* @param array $records
* @return \Illuminate\Database\Eloquent\Model
*/
protected function setEmbedded($records)
{
// Assign models to parent attributes array.
$attributes = $this->parent->getAttributes();
$attributes[$this->localKey] = $records;
// Set raw attributes to skip mutators.
$this->parent->setRawAttributes($attributes);
// Set the relation on the parent.
return $this->parent->setRelation($this->relation, $records === null ? null : $this->getResults());
}
/**
* Get the foreign key value for the relation.
*
* @param mixed $id
* @return mixed
*/
protected function getForeignKeyValue($id)
{
if ($id instanceof Model) {
$id = $id->getKey();
}
// Convert the id to MongoId if necessary.
return $this->getBaseQuery()->convertKey($id);
}
/**
* Convert an array of records to a Collection.
*
* @param array $records
* @return \Illuminate\Database\Eloquent\Collection
*/
protected function toCollection(array $records = [])
{
$models = [];
foreach ($records as $attributes) {
$models[] = $this->toModel($attributes);
}
if (count($models) > 0) {
$models = $this->eagerLoadRelations($models);
}
return new Collection($models);
}
/**
* Create a related model instanced.
*
* @param array $attributes
* @return \Illuminate\Database\Eloquent\Model
*/
protected function toModel($attributes = [])
{
if (is_null($attributes)) {
return;
}
$model = $this->related->newFromBuilder((array) $attributes);
$model->setParentRelation($this);
$model->setRelation($this->foreignKey, $this->parent);
// If you remove this, you will get segmentation faults!
$model->setHidden(array_merge($model->getHidden(), [$this->foreignKey]));
return $model;
}
/**
* Get the relation instance of the parent.
*
* @return \Illuminate\Database\Eloquent\Relations\Relation
*/
protected function getParentRelation()
{
return $this->parent->getParentRelation();
}
/**
* Get the underlying query for the relation.
*
* @return \Illuminate\Database\Eloquent\Builder
*/
public function getQuery()
{
// Because we are sharing this relation instance to models, we need
// to make sure we use separate query instances.
return clone $this->query;
}
/**
* Get the base query builder driving the Eloquent builder.
*
* @return \Illuminate\Database\Query\Builder
*/
public function getBaseQuery()
{
// Because we are sharing this relation instance to models, we need
// to make sure we use separate query instances.
return clone $this->query->getQuery();
}
/**
* Check if this relation is nested in another relation.
*
* @return bool
*/
protected function isNested()
{
return $this->getParentRelation() != null;
}
/**
* Get the fully qualified local key name.
*
* @param string $glue
* @return string
*/
protected function getPathHierarchy($glue = '.')
{
if ($parentRelation = $this->getParentRelation()) {
return $parentRelation->getPathHierarchy($glue) . $glue . $this->localKey;
}
return $this->localKey;
}
/**
* Get the parent's fully qualified key name.
*
* @return string
*/
public function getQualifiedParentKeyName()
{
if ($parentRelation = $this->getParentRelation()) {
return $parentRelation->getPathHierarchy() . '.' . $this->parent->getKeyName();
}
return $this->parent->getKeyName();
}
/**
* Get the primary key value of the parent.
*
* @return string
*/
protected function getParentKey()
{
return $this->parent->getKey();
}
}
<?php namespace Jenssegers\Mongodb\Relations;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Relations\HasMany as EloquentHasMany;
class HasMany extends EloquentHasMany
{
/**
* Add the constraints for a relationship query.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param \Illuminate\Database\Eloquent\Builder $parent
* @param array|mixed $columns
* @return \Illuminate\Database\Eloquent\Builder
*/
public function getRelationQuery(Builder $query, Builder $parent, $columns = ['*'])
{
$query->select($columns);
$key = $this->wrap($this->getQualifiedParentKeyName());
return $query->where($this->getHasCompareKey(), 'exists', true);
}
/**
* Add the constraints for a relationship count query.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param \Illuminate\Database\Eloquent\Builder $parent
* @return \Illuminate\Database\Eloquent\Builder
*/
public function getRelationCountQuery(Builder $query, Builder $parent)
{
$foreignKey = $this->getHasCompareKey();
return $query->select($this->getHasCompareKey())->where($this->getHasCompareKey(), 'exists', true);
}
/**
* Get the plain foreign key.
*
* @return string
*/
public function getPlainForeignKey()
{
return $this->getForeignKey();
}
}
<?php namespace Jenssegers\Mongodb\Relations;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Relations\HasOne as EloquentHasOne;
class HasOne extends EloquentHasOne
{
/**
* Add the constraints for a relationship query.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param \Illuminate\Database\Eloquent\Builder $parent
* @param array|mixed $columns
* @return \Illuminate\Database\Eloquent\Builder
*/
public function getRelationQuery(Builder $query, Builder $parent, $columns = ['*'])
{
$query->select($columns);
$key = $this->wrap($this->getQualifiedParentKeyName());
return $query->where($this->getHasCompareKey(), 'exists', true);
}
/**
* Add the constraints for a relationship count query.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param \Illuminate\Database\Eloquent\Builder $parent
* @return \Illuminate\Database\Eloquent\Builder
*/
public function getRelationCountQuery(Builder $query, Builder $parent)
{
$foreignKey = $this->getHasCompareKey();
return $query->select($this->getHasCompareKey())->where($this->getHasCompareKey(), 'exists', true);
}
/**
* Get the plain foreign key.
*
* @return string
*/
public function getPlainForeignKey()
{
return $this->getForeignKey();
}
}
<?php namespace Jenssegers\Mongodb\Relations;
use Illuminate\Database\Eloquent\Relations\MorphTo as EloquentMorphTo;
class MorphTo extends EloquentMorphTo
{
/**
* Set the base constraints on the relation query.
*/
public function addConstraints()
{
if (static::$constraints) {
// For belongs to relationships, which are essentially the inverse of has one
// or has many relationships, we need to actually query on the primary key
// of the related models matching on the foreign key that's on a parent.
$this->query->where($this->otherKey, '=', $this->parent->{$this->foreignKey});
}
}
/**
* Get all of the relation results for a type.
*
* @param string $type
* @return \Illuminate\Database\Eloquent\Collection
*/
protected function getResultsByType($type)
{
$instance = $this->createModelByType($type);
$key = $instance->getKeyName();
$query = $instance->newQuery();
$query = $this->useWithTrashed($query);
return $query->whereIn($key, $this->gatherKeysByType($type)->all())->get();
}
}
<?php namespace Jenssegers\Mongodb\Schema;
use Closure;
use Illuminate\Database\Connection;
class Blueprint extends \Illuminate\Database\Schema\Blueprint
{
/**
* The MongoConnection object for this blueprint.
*
* @var MongoConnection
*/
protected $connection;
/**
* The MongoCollection object for this blueprint.
*
* @var MongoCollection
*/
protected $collection;
/**
* Fluent columns.
*
* @var array
*/
protected $columns = [];
/**
* Create a new schema blueprint.
*
* @param string $table
* @param Closure $callback
*/
public function __construct(Connection $connection, $collection)
{
$this->connection = $connection;
$this->collection = $connection->getCollection($collection);
}
/**
* Specify an index for the collection.
*
* @param string|array $columns
* @param array $options
* @return Blueprint
*/
public function index($columns = null, $options = [])
{
$columns = $this->fluent($columns);
// Columns are passed as a default array.
if (is_array($columns) && is_int(key($columns))) {
// Transform the columns to the required array format.
$transform = [];
foreach ($columns as $column) {
$transform[$column] = 1;
}
$columns = $transform;
}
$this->collection->ensureIndex($columns, $options);
return $this;
}
/**
* Specify the primary key(s) for the table.
*
* @param string|array $columns
* @param array $options
* @return \Illuminate\Support\Fluent
*/
public function primary($columns = null, $options = [])
{
return $this->unique($columns, $options);
}
/**
* Indicate that the given index should be dropped.
*
* @param string|array $columns
* @return Blueprint
*/
public function dropIndex($columns = null)
{
$columns = $this->fluent($columns);
// Columns are passed as a default array.
if (is_array($columns) && is_int(key($columns))) {
// Transform the columns to the required array format.
$transform = [];
foreach ($columns as $column) {
$transform[$column] = 1;
}
$columns = $transform;
}
$this->collection->deleteIndex($columns);
return $this;
}
/**
* Specify a unique index for the collection.
*
* @param string|array $columns
* @param array $options
* @return Blueprint
*/
public function unique($columns = null, $options = [])
{
$columns = $this->fluent($columns);
$options['unique'] = true;
$this->index($columns, $options);
return $this;
}
/**
* Specify a non blocking index for the collection.
*
* @param string|array $columns
* @return Blueprint
*/
public function background($columns = null)
{
$columns = $this->fluent($columns);
$this->index($columns, ['background' => true]);
return $this;
}
/**
* Specify a sparse index for the collection.
*
* @param string|array $columns
* @param array $options
* @return Blueprint
*/
public function sparse($columns = null, $options = [])
{
$columns = $this->fluent($columns);
$options['sparse'] = true;
$this->index($columns, $options);
return $this;
}
/**
* Specify the number of seconds after wich a document should be considered expired based,
* on the given single-field index containing a date.
*
* @param string|array $columns
* @param int $seconds
* @return Blueprint
*/
public function expire($columns, $seconds)
{
$columns = $this->fluent($columns);
$this->index($columns, ['expireAfterSeconds' => $seconds]);
return $this;
}
/**
* Indicate that the table needs to be created.
*
* @return bool
*/
public function create()
{
$collection = $this->collection->getName();
$db = $this->connection->getMongoDB();
// Ensure the collection is created.
$db->createCollection($collection);
}
/**
* Indicate that the collection should be dropped.
*
* @return bool
*/
public function drop()
{
$this->collection->drop();
}
/**
* Add a new column to the blueprint.
*
* @param string $type
* @param string $name
* @param array $parameters
* @return Blueprint
*/
protected function addColumn($type, $name, array $parameters = [])
{
$this->fluent($name);
return $this;
}
/**
* Allow fluent columns.
*
* @param string|array $columns
* @return string|array
*/
protected function fluent($columns = null)
{
if (is_null($columns)) {
return $this->columns;
} elseif (is_string($columns)) {
return $this->columns = [$columns];
} else {
return $this->columns = $columns;
}
}
/**
* Allows the use of unsupported schema methods.
*
* @return Blueprint
*/
public function __call($method, $args)
{
// Dummy.
return $this;
}
}
<?php namespace Jenssegers\Mongodb\Schema;
use Closure;
use Jenssegers\Mongodb\Connection;
class Builder extends \Illuminate\Database\Schema\Builder
{
/**
* Create a new database Schema manager.
*
* @param Connection $connection
*/
public function __construct(Connection $connection)
{
$this->connection = $connection;
}
/**
* Determine if the given table has a given column.
*
* @param string $table
* @param string $column
* @return bool
*/
public function hasColumn($table, $column)
{
return true;
}
/**
* Determine if the given table has given columns.
*
* @param string $table
* @param array $columns
* @return bool
*/
public function hasColumns($table, array $columns)
{
return true;
}
/**
* Determine if the given collection exists.
*
* @param string $collection
* @return bool
*/
public function hasCollection($collection)
{
$db = $this->connection->getMongoDB();
return in_array($collection, $db->getCollectionNames());
}
/**
* Determine if the given collection exists.
*
* @param string $collection
* @return bool
*/
public function hasTable($collection)
{
return $this->hasCollection($collection);
}
/**
* Modify a collection on the schema.
*
* @param string $collection
* @param Closure $callback
* @return bool
*/
public function collection($collection, Closure $callback)
{
$blueprint = $this->createBlueprint($collection);
if ($callback) {
$callback($blueprint);
}
}
/**
* Modify a collection on the schema.
*
* @param string $collection
* @param Closure $callback
* @return bool
*/
public function table($collection, Closure $callback)
{
return $this->collection($collection, $callback);
}
/**
* Create a new collection on the schema.
*
* @param string $collection
* @param Closure $callback
* @return bool
*/
public function create($collection, Closure $callback = null)
{
$blueprint = $this->createBlueprint($collection);
$blueprint->create();
if ($callback) {
$callback($blueprint);
}
}
/**
* Drop a collection from the schema.
*
* @param string $collection
* @return bool
*/
public function drop($collection)
{
$blueprint = $this->createBlueprint($collection);
return $blueprint->drop();
}
/**
* Create a new Blueprint.
*
* @param string $collection
* @return Schema\Blueprint
*/
protected function createBlueprint($collection, Closure $callback = null)
{
return new Blueprint($this->connection, $collection);
}
}
<?php require 'vendor/autoload.php';
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment