Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
L
laravel-mongodb
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
sinan
laravel-mongodb
Commits
a045497b
Commit
a045497b
authored
Apr 27, 2014
by
Jens Segers
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Adding first step to embedsOne
parent
78c4ae06
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
615 additions
and
386 deletions
+615
-386
Model.php
src/Jenssegers/Mongodb/Model.php
+37
-0
EmbedsMany.php
src/Jenssegers/Mongodb/Relations/EmbedsMany.php
+22
-381
EmbedsOne.php
src/Jenssegers/Mongodb/Relations/EmbedsOne.php
+99
-0
EmbedsOneOrMany.php
src/Jenssegers/Mongodb/Relations/EmbedsOneOrMany.php
+381
-0
RelationsTest.php
tests/RelationsTest.php
+71
-5
User.php
tests/models/User.php
+5
-0
No files found.
src/Jenssegers/Mongodb/Model.php
View file @
a045497b
...
@@ -5,6 +5,7 @@ use Jenssegers\Mongodb\DatabaseManager as Resolver;
...
@@ -5,6 +5,7 @@ use Jenssegers\Mongodb\DatabaseManager as Resolver;
use
Jenssegers\Mongodb\Eloquent\Builder
;
use
Jenssegers\Mongodb\Eloquent\Builder
;
use
Jenssegers\Mongodb\Query\Builder
as
QueryBuilder
;
use
Jenssegers\Mongodb\Query\Builder
as
QueryBuilder
;
use
Jenssegers\Mongodb\Relations\EmbedsMany
;
use
Jenssegers\Mongodb\Relations\EmbedsMany
;
use
Jenssegers\Mongodb\Relations\EmbedsOne
;
use
Carbon\Carbon
;
use
Carbon\Carbon
;
use
DateTime
;
use
DateTime
;
...
@@ -84,6 +85,42 @@ abstract class Model extends \Jenssegers\Eloquent\Model {
...
@@ -84,6 +85,42 @@ abstract class Model extends \Jenssegers\Eloquent\Model {
return
new
EmbedsMany
(
$query
,
$this
,
$instance
,
$localKey
,
$foreignKey
,
$relation
);
return
new
EmbedsMany
(
$query
,
$this
,
$instance
,
$localKey
,
$foreignKey
,
$relation
);
}
}
/**
* Define an embedded one-to-many relationship.
*
* @param string $related
* @param string $collection
* @return \Illuminate\Database\Eloquent\Relations\EmbedsMany
*/
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.
* Convert a DateTime to a storable MongoDate object.
*
*
...
...
src/Jenssegers/Mongodb/Relations/EmbedsMany.php
View file @
a045497b
This diff is collapsed.
Click to expand it.
src/Jenssegers/Mongodb/Relations/EmbedsOne.php
0 → 100644
View file @
a045497b
<?php
namespace
Jenssegers\Mongodb\Relations
;
use
Illuminate\Database\Eloquent\Model
;
use
Illuminate\Database\Eloquent\Builder
;
use
Illuminate\Database\Eloquent\Relations\Relation
;
use
Illuminate\Database\Eloquent\Collection
;
use
MongoId
;
class
EmbedsOne
extends
EmbedsOneOrMany
{
/**
* Get the results of the relationship.
*
* @return Illuminate\Database\Eloquent\Collection
*/
public
function
getResults
()
{
return
$this
->
toModel
(
$this
->
getEmbedded
());
}
/**
* Check if a model is already embedded.
*
* @param mixed $key
* @return bool
*/
public
function
contains
(
$key
)
{
if
(
$key
instanceof
Model
)
$key
=
$key
->
getKey
();
$embedded
=
$this
->
getEmbedded
();
$primaryKey
=
$this
->
related
->
getKeyName
();
return
(
$embedded
and
$embedded
[
$primaryKey
]
==
$key
);
}
/**
* Save a new model and attach it to the parent model.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @return \Illuminate\Database\Eloquent\Model
*/
protected
function
performInsert
(
Model
$model
)
{
// Create a new key if needed.
if
(
!
$model
->
getAttribute
(
'_id'
))
{
$model
->
setAttribute
(
'_id'
,
new
MongoId
);
}
$result
=
$this
->
query
->
update
(
array
(
$this
->
localKey
=>
$model
->
getAttributes
()));
if
(
$result
)
$this
->
setEmbedded
(
$model
->
getAttributes
());
return
$result
?
$model
:
false
;
}
/**
* Save an existing model and attach it to the parent model.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @return Model|bool
*/
protected
function
performUpdate
(
Model
$model
)
{
$result
=
$this
->
query
->
update
(
array
(
$this
->
localKey
=>
$model
->
getAttributes
()));
if
(
$result
)
$this
->
setEmbedded
(
$model
->
getAttributes
());
return
$result
?
$model
:
false
;
}
/**
* Delete all embedded models.
*
* @return int
*/
public
function
delete
()
{
// Overwrite the local key with an empty array.
$result
=
$this
->
query
->
update
(
array
(
$this
->
localKey
=>
null
));
// If the update query was successful, we will remove the embedded records
// of the parent instance.
if
(
$result
)
{
$count
=
$this
->
count
();
$this
->
setEmbedded
(
null
);
// Return the number of deleted embedded records.
return
$count
;
}
return
$result
;
}
}
src/Jenssegers/Mongodb/Relations/EmbedsOneOrMany.php
0 → 100644
View file @
a045497b
<?php
namespace
Jenssegers\Mongodb\Relations
;
use
Illuminate\Database\Eloquent\Model
;
use
Illuminate\Database\Eloquent\Builder
;
use
Illuminate\Database\Eloquent\Relations\Relation
;
use
Illuminate\Database\Eloquent\Collection
;
use
MongoId
;
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 string $localKey
* @param string $foreignKey
* @param string $relation
* @return void
*/
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
;
$this
->
addConstraints
();
}
/**
* Set the base constraints on the relation query.
*
* @return void
*/
public
function
addConstraints
()
{
if
(
static
::
$constraints
)
{
$this
->
query
->
where
(
$this
->
parent
->
getKeyName
(),
'='
,
$this
->
parent
->
getKey
());
}
}
/**
* Set the constraints for an eager load of the relation.
*
* @param array $models
* @return void
*/
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
* @return void
*/
public
function
initRelation
(
array
$models
,
$relation
)
{
foreach
(
$models
as
$model
)
{
$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
->
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
)
{
if
(
$this
->
fireModelEvent
(
$model
,
'saving'
)
===
false
)
return
false
;
$this
->
updateTimestamps
(
$model
);
// Attach a new model.
if
(
!
$this
->
contains
(
$model
))
{
if
(
$this
->
fireModelEvent
(
$model
,
'creating'
)
===
false
)
return
false
;
$result
=
$this
->
performInsert
(
$model
);
if
(
$result
)
{
$this
->
fireModelEvent
(
$model
,
'created'
,
false
);
// Mark model as existing
$model
->
exists
=
true
;
}
}
// Update an existing model.
else
{
if
(
$this
->
fireModelEvent
(
$model
,
'updating'
)
===
false
)
return
false
;
$result
=
$this
->
performUpdate
(
$model
);
if
(
$result
)
$this
->
fireModelEvent
(
$model
,
'updated'
,
false
);
}
if
(
$result
)
{
$this
->
fireModelEvent
(
$result
,
'saved'
,
false
);
return
$result
;
}
return
false
;
}
/**
* 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
();
$instance
->
setRawAttributes
(
$attributes
);
return
$this
->
save
(
$instance
);
}
/**
* Attach an array of models to the parent instance.
*
* @param array $models
* @return array
*/
public
function
saveMany
(
array
$models
)
{
array_walk
(
$models
,
array
(
$this
,
'save'
));
return
$models
;
}
/**
* Create an array of new instances of the related model.
*
* @param array $records
* @return array
*/
public
function
createMany
(
array
$records
)
{
$instances
=
array_map
(
array
(
$this
,
'create'
),
$records
);
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
(
!
is_array
(
$ids
))
$ids
=
array
(
$ids
);
foreach
(
$ids
as
&
$id
)
{
if
(
$id
instanceof
Model
)
$id
=
$id
->
getKey
();
}
return
$ids
;
}
/**
* Create a related model instanced.
*
* @param array $attributes [description]
* @return [type] [description]
*/
protected
function
toModel
(
$attributes
=
array
())
{
if
(
is_null
(
$attributes
))
return
null
;
$model
=
$this
->
related
->
newFromBuilder
((
array
)
$attributes
);
// Attatch the parent relation to the embedded model.
$model
->
setRelation
(
$this
->
foreignKey
,
$this
->
parent
);
$model
->
setHidden
(
array_merge
(
$model
->
getHidden
(),
array
(
$this
->
foreignKey
)));
return
$model
;
}
/**
* Get the embedded records array.
*
* @return array
*/
protected
function
getEmbedded
()
{
// Get raw attributes to skip relations and accessors.
$attributes
=
$this
->
parent
->
getAttributes
();
return
isset
(
$attributes
[
$this
->
localKey
])
?
$attributes
[
$this
->
localKey
]
:
null
;
}
/**
* Set the embedded records array.
*
* @param array $models
* @return void
*/
protected
function
setEmbedded
(
$data
)
{
$attributes
=
$this
->
parent
->
getAttributes
();
$attributes
[
$this
->
localKey
]
=
$data
;
// Set raw attributes to skip mutators.
$this
->
parent
->
setRawAttributes
(
$attributes
);
// Set the relation on the parent.
$this
->
parent
->
setRelation
(
$this
->
relation
,
$this
->
getResults
());
}
/**
* Update the creation and update timestamps.
*
* @return void
*/
protected
function
updateTimestamps
(
Model
$model
)
{
$time
=
$model
->
freshTimestamp
();
if
(
!
$model
->
isDirty
(
Model
::
UPDATED_AT
))
{
$model
->
setUpdatedAt
(
$time
);
}
if
(
!
$model
->
exists
&&
!
$model
->
isDirty
(
Model
::
CREATED_AT
))
{
$model
->
setCreatedAt
(
$time
);
}
}
/**
* 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
=
array
())
{
$models
=
array
();
// Wrap records in model objects.
foreach
(
$records
as
$attributes
)
{
$models
[]
=
$this
->
toModel
(
$attributes
);
}
if
(
count
(
$models
)
>
0
)
{
$models
=
$this
->
eagerLoadRelations
(
$models
);
}
return
$this
->
related
->
newCollection
(
$models
);
}
/**
* Fire the given event for the given model.
*
* @param string $event
* @param bool $halt
* @return mixed
*/
protected
function
fireModelEvent
(
Model
$model
,
$event
,
$halt
=
true
)
{
$dispatcher
=
$model
->
getEventDispatcher
();
if
(
is_null
(
$dispatcher
))
return
true
;
// We will append the names of the class to the event to distinguish it from
// other model events that are fired, allowing us to listen on each model
// event set individually instead of catching event for all the models.
$event
=
"eloquent.
{
$event
}
: "
.
get_class
(
$model
);
$method
=
$halt
?
'until'
:
'fire'
;
return
$dispatcher
->
$method
(
$event
,
$model
);
}
}
tests/RelationsTest.php
View file @
a045497b
...
@@ -595,15 +595,19 @@ class RelationsTest extends TestCase {
...
@@ -595,15 +595,19 @@ class RelationsTest extends TestCase {
public
function
testEmbedsManyEagerLoading
()
public
function
testEmbedsManyEagerLoading
()
{
{
$user
=
User
::
create
(
array
(
'name'
=>
'John Doe'
));
$user
1
=
User
::
create
(
array
(
'name'
=>
'John Doe'
));
$
address1
=
$user
->
addresses
()
->
save
(
new
Address
(
array
(
'city'
=>
'New York'
)));
$
user1
->
addresses
()
->
save
(
new
Address
(
array
(
'city'
=>
'New York'
)));
$
address2
=
$user
->
addresses
()
->
save
(
new
Address
(
array
(
'city'
=>
'Paris'
)));
$
user1
->
addresses
()
->
save
(
new
Address
(
array
(
'city'
=>
'Paris'
)));
$user
=
User
::
find
(
$user
->
id
);
$user2
=
User
::
create
(
array
(
'name'
=>
'Jane Doe'
));
$user2
->
addresses
()
->
save
(
new
Address
(
array
(
'city'
=>
'Berlin'
)));
$user2
->
addresses
()
->
save
(
new
Address
(
array
(
'city'
=>
'Paris'
)));
$user
=
User
::
find
(
$user1
->
id
);
$relations
=
$user
->
getRelations
();
$relations
=
$user
->
getRelations
();
$this
->
assertFalse
(
array_key_exists
(
'addresses'
,
$relations
));
$this
->
assertFalse
(
array_key_exists
(
'addresses'
,
$relations
));
$user
=
User
::
with
(
'addresses'
)
->
find
(
$user
->
id
);
$user
=
User
::
with
(
'addresses'
)
->
get
()
->
first
(
);
$relations
=
$user
->
getRelations
();
$relations
=
$user
->
getRelations
();
$this
->
assertTrue
(
array_key_exists
(
'addresses'
,
$relations
));
$this
->
assertTrue
(
array_key_exists
(
'addresses'
,
$relations
));
$this
->
assertEquals
(
2
,
$relations
[
'addresses'
]
->
count
());
$this
->
assertEquals
(
2
,
$relations
[
'addresses'
]
->
count
());
...
@@ -633,4 +637,66 @@ class RelationsTest extends TestCase {
...
@@ -633,4 +637,66 @@ class RelationsTest extends TestCase {
$this
->
assertEquals
(
2
,
$user2
->
addresses
->
count
());
$this
->
assertEquals
(
2
,
$user2
->
addresses
->
count
());
}
}
public
function
testEmbedsOne
()
{
$user
=
User
::
create
(
array
(
'name'
=>
'John Doe'
));
$father
=
new
User
(
array
(
'name'
=>
'Mark Doe'
));
$father
->
setEventDispatcher
(
$events
=
Mockery
::
mock
(
'Illuminate\Events\Dispatcher'
));
$events
->
shouldReceive
(
'until'
)
->
once
()
->
with
(
'eloquent.saving: '
.
get_class
(
$father
),
$father
)
->
andReturn
(
true
);
$events
->
shouldReceive
(
'until'
)
->
once
()
->
with
(
'eloquent.creating: '
.
get_class
(
$father
),
$father
)
->
andReturn
(
true
);
$events
->
shouldReceive
(
'fire'
)
->
once
()
->
with
(
'eloquent.created: '
.
get_class
(
$father
),
$father
);
$events
->
shouldReceive
(
'fire'
)
->
once
()
->
with
(
'eloquent.saved: '
.
get_class
(
$father
),
$father
);
$father
=
$user
->
father
()
->
save
(
$father
);
$father
->
unsetEventDispatcher
();
$this
->
assertNotNull
(
$user
->
_father
);
$this
->
assertEquals
(
'Mark Doe'
,
$user
->
father
->
name
);
$this
->
assertInstanceOf
(
'DateTime'
,
$father
->
created_at
);
$this
->
assertInstanceOf
(
'DateTime'
,
$father
->
updated_at
);
$this
->
assertNotNull
(
$father
->
_id
);
$this
->
assertTrue
(
is_string
(
$father
->
_id
));
$raw
=
$father
->
getAttributes
();
$this
->
assertInstanceOf
(
'MongoId'
,
$raw
[
'_id'
]);
$father
->
setEventDispatcher
(
$events
=
Mockery
::
mock
(
'Illuminate\Events\Dispatcher'
));
$events
->
shouldReceive
(
'until'
)
->
once
()
->
with
(
'eloquent.saving: '
.
get_class
(
$father
),
$father
)
->
andReturn
(
true
);
$events
->
shouldReceive
(
'until'
)
->
once
()
->
with
(
'eloquent.updating: '
.
get_class
(
$father
),
$father
)
->
andReturn
(
true
);
$events
->
shouldReceive
(
'fire'
)
->
once
()
->
with
(
'eloquent.updated: '
.
get_class
(
$father
),
$father
);
$events
->
shouldReceive
(
'fire'
)
->
once
()
->
with
(
'eloquent.saved: '
.
get_class
(
$father
),
$father
);
$father
->
name
=
'Tom Doe'
;
$user
->
father
()
->
save
(
$father
);
$father
->
unsetEventDispatcher
();
$this
->
assertNotNull
(
$user
->
_father
);
$this
->
assertEquals
(
'Tom Doe'
,
$user
->
father
->
name
);
$father
=
new
User
(
array
(
'name'
=>
'Jim Doe'
));
$father
->
setEventDispatcher
(
$events
=
Mockery
::
mock
(
'Illuminate\Events\Dispatcher'
));
$events
->
shouldReceive
(
'until'
)
->
once
()
->
with
(
'eloquent.saving: '
.
get_class
(
$father
),
$father
)
->
andReturn
(
true
);
$events
->
shouldReceive
(
'until'
)
->
once
()
->
with
(
'eloquent.creating: '
.
get_class
(
$father
),
$father
)
->
andReturn
(
true
);
$events
->
shouldReceive
(
'fire'
)
->
once
()
->
with
(
'eloquent.created: '
.
get_class
(
$father
),
$father
);
$events
->
shouldReceive
(
'fire'
)
->
once
()
->
with
(
'eloquent.saved: '
.
get_class
(
$father
),
$father
);
$father
=
$user
->
father
()
->
save
(
$father
);
$father
->
unsetEventDispatcher
();
$this
->
assertNotNull
(
$user
->
_father
);
$this
->
assertEquals
(
'Jim Doe'
,
$user
->
father
->
name
);
}
public
function
testEmbedsOneDelete
()
{
$user
=
User
::
create
(
array
(
'name'
=>
'John Doe'
));
$father
=
$user
->
father
()
->
save
(
new
User
(
array
(
'name'
=>
'Mark Doe'
)));
$user
->
father
()
->
delete
();
$this
->
assertNull
(
$user
->
_father
);
$this
->
assertNull
(
$user
->
father
);
}
}
}
tests/models/User.php
View file @
a045497b
...
@@ -55,6 +55,11 @@ class User extends Eloquent implements UserInterface, RemindableInterface {
...
@@ -55,6 +55,11 @@ class User extends Eloquent implements UserInterface, RemindableInterface {
return
$this
->
embedsMany
(
'Address'
);
return
$this
->
embedsMany
(
'Address'
);
}
}
public
function
father
()
{
return
$this
->
embedsOne
(
'User'
);
}
/**
/**
* Get the unique identifier for the user.
* Get the unique identifier for the user.
*
*
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment