Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
Y
yii2
Project
Overview
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
PSDI Army
yii2
Commits
c6347d6d
Commit
c6347d6d
authored
Nov 23, 2013
by
Carsten Brandt
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
polished elasticsearch AR api, added mget and fixed AR::equals()
parent
426223af
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
283 additions
and
26 deletions
+283
-26
ActiveRecord.php
framework/yii/db/ActiveRecord.php
+6
-2
ActiveRecord.php
framework/yii/elasticsearch/ActiveRecord.php
+110
-10
Command.php
framework/yii/elasticsearch/Command.php
+30
-0
ActiveRecordTest.php
tests/unit/framework/db/ActiveRecordTest.php
+33
-0
ActiveRecordTest.php
tests/unit/framework/elasticsearch/ActiveRecordTest.php
+71
-14
ActiveRecordTest.php
tests/unit/framework/redis/ActiveRecordTest.php
+33
-0
No files found.
framework/yii/db/ActiveRecord.php
View file @
c6347d6d
...
...
@@ -132,7 +132,7 @@ class ActiveRecord extends Model
* - an array of name-value pairs: query by a set of column values and return a single record matching all of them.
* - null: return a new [[ActiveQuery]] object for further query purpose.
*
* @return ActiveQuery|Active
Record
|null When `$q` is null, a new [[ActiveQuery]] instance
* @return ActiveQuery|Active
QueryInterface|static
|null When `$q` is null, a new [[ActiveQuery]] instance
* is returned; when `$q` is a scalar or an array, an ActiveRecord object matching it will be
* returned (null will be returned if there is no matching).
* @throws InvalidConfigException if the AR class does not have a primary key
...
...
@@ -754,7 +754,7 @@ class ActiveRecord extends Model
* [[EVENT_BEFORE_INSERT]], [[EVENT_AFTER_INSERT]] and [[EVENT_AFTER_VALIDATE]]
* will be raised by the corresponding methods.
*
* Only the [[
changed
Attributes|changed attribute values]] will be inserted into database.
* Only the [[
dirty
Attributes|changed attribute values]] will be inserted into database.
*
* If the table's primary key is auto-incremental and is null during insertion,
* it will be populated with the actual value after insertion.
...
...
@@ -1179,11 +1179,15 @@ class ActiveRecord extends Model
/**
* Returns a value indicating whether the given active record is the same as the current one.
* The comparison is made by comparing the table names and the primary key values of the two active records.
* If one of the records [[isNewRecord|is new]] they are also considered not equal.
* @param ActiveRecord $record record to compare to
* @return boolean whether the two active records refer to the same row in the same database table.
*/
public
function
equals
(
$record
)
{
if
(
$this
->
isNewRecord
||
$record
->
isNewRecord
)
{
return
false
;
}
return
$this
->
tableName
()
===
$record
->
tableName
()
&&
$this
->
getPrimaryKey
()
===
$record
->
getPrimaryKey
();
}
...
...
framework/yii/elasticsearch/ActiveRecord.php
View file @
c6347d6d
...
...
@@ -25,7 +25,7 @@ use yii\helpers\StringHelper;
* @author Carsten Brandt <mail@cebe.cc>
* @since 2.0
*/
abstract
class
ActiveRecord
extends
\yii\db\ActiveRecord
class
ActiveRecord
extends
\yii\db\ActiveRecord
{
private
$_id
;
private
$_version
;
...
...
@@ -48,7 +48,7 @@ abstract class ActiveRecord extends \yii\db\ActiveRecord
{
$query
=
static
::
createQuery
();
if
(
is_array
(
$q
))
{
if
(
count
(
$q
)
==
1
&&
isset
(
$q
[
'primaryKey'
]
))
{
if
(
count
(
$q
)
==
1
&&
(
array_key_exists
(
'primaryKey'
,
$q
)
))
{
return
static
::
get
(
$q
[
'primaryKey'
]);
}
return
$query
->
where
(
$q
)
->
one
();
...
...
@@ -58,8 +58,23 @@ abstract class ActiveRecord extends \yii\db\ActiveRecord
return
$query
;
}
/**
* Gets a record by its primary key.
*
* @param mixed $primaryKey the primaryKey value
* @param array $options options given in this parameter are passed to elasticsearch
* as request URI parameters.
*
* Please refer to the [elasticsearch documentation](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/docs-get.html)
* for more details on these options.
* @return static|null The record instance or null if it was not found.
*/
public
static
function
get
(
$primaryKey
,
$options
=
[])
{
if
(
$primaryKey
===
null
)
{
return
null
;
}
$command
=
static
::
getDb
()
->
createCommand
();
$result
=
$command
->
get
(
static
::
index
(),
static
::
type
(),
$primaryKey
,
$options
);
if
(
$result
[
'exists'
])
{
...
...
@@ -69,6 +84,34 @@ abstract class ActiveRecord extends \yii\db\ActiveRecord
}
/**
* Gets a list of records by its primary keys.
*
* @param array $primaryKeys an array of primaryKey values
* @param array $options options given in this parameter are passed to elasticsearch
* as request URI parameters.
*
* Please refer to the [elasticsearch documentation](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/docs-get.html)
* for more details on these options.
* @return static|null The record instance or null if it was not found.
*/
public
static
function
mget
(
$primaryKeys
,
$options
=
[])
{
if
(
empty
(
$primaryKeys
))
{
return
[];
}
$command
=
static
::
getDb
()
->
createCommand
();
$result
=
$command
->
mget
(
static
::
index
(),
static
::
type
(),
$primaryKeys
,
$options
);
$models
=
[];
foreach
(
$result
[
'docs'
]
as
$doc
)
{
if
(
$doc
[
'exists'
])
{
$models
[]
=
static
::
create
(
$doc
);
}
}
return
$models
;
}
/**
* @inheritDoc
*/
public
static
function
createQuery
()
...
...
@@ -117,7 +160,12 @@ abstract class ActiveRecord extends \yii\db\ActiveRecord
*/
public
function
getOldPrimaryKey
(
$asArray
=
false
)
{
return
$this
->
getPrimaryKey
(
$asArray
);
$id
=
$this
->
isNewRecord
?
null
:
$this
->
_id
;
if
(
$asArray
)
{
return
[
'primaryKey'
=>
$id
];
}
else
{
return
$this
->
_id
;
}
}
/**
...
...
@@ -142,12 +190,17 @@ abstract class ActiveRecord extends \yii\db\ActiveRecord
throw
new
InvalidConfigException
(
'The attributes() method of elasticsearch ActiveRecord has to be implemented by child classes.'
);
}
// TODO index and type definition
/**
* @return string the name of the index this record is stored in.
*/
public
static
function
index
()
{
return
Inflector
::
pluralize
(
Inflector
::
camel2id
(
StringHelper
::
basename
(
get_called_class
()),
'-'
));
}
/**
* @return string the name of the type of this record.
*/
public
static
function
type
()
{
return
Inflector
::
camel2id
(
StringHelper
::
basename
(
get_called_class
()),
'-'
);
...
...
@@ -168,9 +221,56 @@ abstract class ActiveRecord extends \yii\db\ActiveRecord
}
/**
* @inheritDocs
* Inserts a document into the associated index using the attribute values of this record.
*
* This method performs the following steps in order:
*
* 1. call [[beforeValidate()]] when `$runValidation` is true. If validation
* fails, it will skip the rest of the steps;
* 2. call [[afterValidate()]] when `$runValidation` is true.
* 3. call [[beforeSave()]]. If the method returns false, it will skip the
* rest of the steps;
* 4. insert the record into database. If this fails, it will skip the rest of the steps;
* 5. call [[afterSave()]];
*
* In the above step 1, 2, 3 and 5, events [[EVENT_BEFORE_VALIDATE]],
* [[EVENT_BEFORE_INSERT]], [[EVENT_AFTER_INSERT]] and [[EVENT_AFTER_VALIDATE]]
* will be raised by the corresponding methods.
*
* Only the [[dirtyAttributes|changed attribute values]] will be inserted into database.
*
* If the [[primaryKey|primary key]] is not set (null) during insertion,
* it will be populated with a
* [randomly generated value](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/docs-index_.html#_automatic_id_generation)
* after insertion.
*
* For example, to insert a customer record:
*
* ~~~
* $customer = new Customer;
* $customer->name = $name;
* $customer->email = $email;
* $customer->insert();
* ~~~
*
* @param boolean $runValidation whether to perform validation before saving the record.
* If the validation fails, the record will not be inserted into the database.
* @param array $attributes list of attributes that need to be saved. Defaults to null,
* meaning all attributes will be saved.
* @param array $options options given in this parameter are passed to elasticsearch
* as request URI parameters. These are among others:
*
* - `routing` define shard placement of this record.
* - `parent` by giving the primaryKey of another record this defines a parent-child relation
* - `timestamp` specifies the timestamp to store along with the document. Default is indexing time.
*
* Please refer to the [elasticsearch documentation](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/docs-index_.html)
* for more details on these options.
*
* By default the `op_type` is set to `create`.
* @return boolean whether the attributes are valid and the record is inserted successfully.
*/
public
function
insert
(
$runValidation
=
true
,
$attributes
=
null
)
public
function
insert
(
$runValidation
=
true
,
$attributes
=
null
,
$options
=
[
'op_type'
=>
'create'
]
)
{
if
(
$runValidation
&&
!
$this
->
validate
(
$attributes
))
{
return
false
;
...
...
@@ -182,7 +282,8 @@ abstract class ActiveRecord extends \yii\db\ActiveRecord
static
::
index
(),
static
::
type
(),
$values
,
$this
->
getPrimaryKey
()
$this
->
getPrimaryKey
(),
$options
);
if
(
!
$response
[
'ok'
])
{
...
...
@@ -268,7 +369,7 @@ abstract class ActiveRecord extends \yii\db\ActiveRecord
}
$bulk
=
''
;
foreach
((
array
)
$condition
as
$pk
)
{
$bulk
=
Json
::
encode
([
$bulk
.
=
Json
::
encode
([
"delete"
=>
[
"_id"
=>
$pk
,
"_type"
=>
static
::
type
(),
...
...
@@ -283,10 +384,9 @@ abstract class ActiveRecord extends \yii\db\ActiveRecord
$body
=
Json
::
decode
(
$response
->
getBody
(
true
));
$n
=
0
;
foreach
(
$body
[
'items'
]
as
$item
)
{
if
(
$item
[
'delete'
][
'ok'
])
{
if
(
$item
[
'delete'
][
'
found'
]
&&
$item
[
'delete'
][
'
ok'
])
{
$n
++
;
}
// TODO might want to update the _version in update()
}
return
$n
;
}
...
...
framework/yii/elasticsearch/Command.php
View file @
c6347d6d
...
...
@@ -116,6 +116,36 @@ class Command extends Component
}
/**
* gets multiple documents from the index
*
* TODO allow specifying type and index + fields
* @param $index
* @param $type
* @param $id
* @param array $options
* @return mixed
* @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/docs-get.html
*/
public
function
mget
(
$index
,
$type
,
$ids
,
$options
=
[])
{
$httpOptions
=
[
'exceptions'
=>
false
,
];
$body
=
Json
::
encode
([
'ids'
=>
array_values
(
$ids
)]);
$response
=
$this
->
db
->
http
()
->
post
(
// TODO guzzle does not manage to send get request with content
$this
->
createUrl
([
$index
,
$type
,
'_mget'
],
$options
),
null
,
$body
,
$httpOptions
)
->
send
();
if
(
$response
->
getStatusCode
()
==
200
)
{
return
Json
::
decode
(
$response
->
getBody
(
true
));
}
else
{
throw
new
Exception
(
'Elasticsearch request failed.'
);
}
}
/**
* gets a documents _source from the index (>=v0.90.1)
* @param $index
* @param $type
...
...
tests/unit/framework/db/ActiveRecordTest.php
View file @
c6347d6d
...
...
@@ -104,6 +104,39 @@ class ActiveRecordTest extends DatabaseTestCase
$this
->
assertTrue
(
$customers
[
'3-user3'
]
instanceof
Customer
);
}
public
function
testRefresh
()
{
$customer
=
new
Customer
();
$this
->
assertFalse
(
$customer
->
refresh
());
$customer
=
Customer
::
find
(
1
);
$customer
->
name
=
'to be refreshed'
;
$this
->
assertTrue
(
$customer
->
refresh
());
$this
->
assertEquals
(
'user1'
,
$customer
->
name
);
}
public
function
testEquals
()
{
$customerA
=
new
Customer
();
$customerB
=
new
Customer
();
$this
->
assertFalse
(
$customerA
->
equals
(
$customerB
));
$customerA
=
new
Customer
();
$customerB
=
new
Item
();
$this
->
assertFalse
(
$customerA
->
equals
(
$customerB
));
$customerA
=
Customer
::
find
(
1
);
$customerB
=
Customer
::
find
(
2
);
$this
->
assertFalse
(
$customerA
->
equals
(
$customerB
));
$customerB
=
Customer
::
find
(
1
);
$this
->
assertTrue
(
$customerA
->
equals
(
$customerB
));
$customerA
=
Customer
::
find
(
1
);
$customerB
=
Item
::
find
(
1
);
$this
->
assertFalse
(
$customerA
->
equals
(
$customerB
));
}
public
function
testFindBySql
()
{
// find one
...
...
tests/unit/framework/elasticsearch/ActiveRecordTest.php
View file @
c6347d6d
...
...
@@ -93,17 +93,6 @@ class ActiveRecordTest extends ElasticSearchTestCase
// $orderItem->save(false);
Customer
::
getDb
()
->
createCommand
()
->
flushIndex
();
// for($n = 0; $n < 20; $n++) {
// $r = $db->http()->post('_count')->send();
// $c = Json::decode($r->getBody(true));
// if ($c['count'] != 11) {
// usleep(100000);
// } else {
// return;
// }
// }
// throw new \Exception('Unable to initialize elasticsearch data.');
}
public
function
testFind
()
...
...
@@ -187,6 +176,62 @@ class ActiveRecordTest extends ElasticSearchTestCase
$this
->
assertTrue
(
$customers
[
'2-user3'
]
instanceof
Customer
);
}
public
function
testGet
()
{
$this
->
assertInstanceOf
(
Customer
::
className
(),
Customer
::
get
(
1
));
$this
->
assertNull
(
Customer
::
get
(
5
));
}
public
function
testMget
()
{
$this
->
assertEquals
([],
Customer
::
mget
([]));
$records
=
Customer
::
mget
([
1
]);
$this
->
assertEquals
(
1
,
count
(
$records
));
$this
->
assertInstanceOf
(
Customer
::
className
(),
reset
(
$records
));
$records
=
Customer
::
mget
([
5
]);
$this
->
assertEquals
(
0
,
count
(
$records
));
$records
=
Customer
::
mget
([
1
,
3
,
5
]);
$this
->
assertEquals
(
2
,
count
(
$records
));
$this
->
assertInstanceOf
(
Customer
::
className
(),
$records
[
0
]);
$this
->
assertInstanceOf
(
Customer
::
className
(),
$records
[
1
]);
}
public
function
testRefresh
()
{
$customer
=
new
Customer
();
$this
->
assertFalse
(
$customer
->
refresh
());
$customer
=
Customer
::
get
(
1
);
$customer
->
name
=
'to be refreshed'
;
$this
->
assertTrue
(
$customer
->
refresh
());
$this
->
assertEquals
(
'user1'
,
$customer
->
name
);
}
public
function
testEquals
()
{
$customerA
=
new
Customer
();
$customerB
=
new
Customer
();
$this
->
assertFalse
(
$customerA
->
equals
(
$customerB
));
$customerA
=
new
Customer
();
$customerB
=
new
Item
();
$this
->
assertFalse
(
$customerA
->
equals
(
$customerB
));
$customerA
=
Customer
::
find
(
1
);
$customerB
=
Customer
::
find
(
2
);
$this
->
assertFalse
(
$customerA
->
equals
(
$customerB
));
$customerB
=
Customer
::
find
(
1
);
$this
->
assertTrue
(
$customerA
->
equals
(
$customerB
));
$customerA
=
Customer
::
find
(
1
);
$customerB
=
Item
::
find
(
1
);
$this
->
assertFalse
(
$customerA
->
equals
(
$customerB
));
}
public
function
testFindCount
()
{
$this
->
assertEquals
(
3
,
Customer
::
find
()
->
count
());
...
...
@@ -388,6 +433,8 @@ class ActiveRecordTest extends ElasticSearchTestCase
public
function
testInsertNoPk
()
{
$this
->
assertEquals
([
'primaryKey'
],
Customer
::
primaryKey
());
$customer
=
new
Customer
;
$customer
->
email
=
'user4@example.com'
;
$customer
->
name
=
'user4'
;
...
...
@@ -435,17 +482,20 @@ class ActiveRecordTest extends ElasticSearchTestCase
// updateAll
$customer
=
Customer
::
find
(
3
);
$this
->
assertEquals
(
'user3'
,
$customer
->
name
);
$ret
=
Customer
::
updateAll
(
array
(
$ret
=
Customer
::
updateAll
(
[
'name'
=>
'temp'
,
),
array
(
'id'
=>
3
)
);
],
[
'id'
=>
3
]
);
$this
->
assertEquals
(
1
,
$ret
);
$customer
=
Customer
::
find
(
3
);
$this
->
assertEquals
(
'temp'
,
$customer
->
name
);
$ret
=
Customer
::
updateAll
([
'name'
=>
'temp'
]);
$this
->
assertEquals
(
0
,
$ret
);
}
public
function
testUpdatePk
()
{
$this
->
setExpectedException
(
'yii\base\
NotSupported
Exception'
);
$this
->
setExpectedException
(
'yii\base\
InvalidCall
Exception'
);
$pk
=
array
(
'primaryKey'
=>
2
);
$orderItem
=
Order
::
find
(
$pk
);
...
...
@@ -472,7 +522,13 @@ class ActiveRecordTest extends ElasticSearchTestCase
$this
->
assertEquals
(
2
,
count
(
$customers
));
$ret
=
Customer
::
deleteAll
([
1
,
2
,
3
]);
$this
->
assertEquals
(
2
,
$ret
);
Customer
::
getDb
()
->
createCommand
()
->
flushIndex
(
'customers'
);
$customers
=
Customer
::
find
()
->
all
();
$this
->
assertEquals
(
0
,
count
(
$customers
));
$ret
=
Customer
::
deleteAll
();
$this
->
assertEquals
(
0
,
$ret
);
}
}
\ No newline at end of file
tests/unit/framework/redis/ActiveRecordTest.php
View file @
c6347d6d
...
...
@@ -161,6 +161,39 @@ class ActiveRecordTest extends RedisTestCase
$this
->
assertTrue
(
$customers
[
'3-user3'
]
instanceof
Customer
);
}
public
function
testRefresh
()
{
$customer
=
new
Customer
();
$this
->
assertFalse
(
$customer
->
refresh
());
$customer
=
Customer
::
find
(
1
);
$customer
->
name
=
'to be refreshed'
;
$this
->
assertTrue
(
$customer
->
refresh
());
$this
->
assertEquals
(
'user1'
,
$customer
->
name
);
}
public
function
testEquals
()
{
$customerA
=
new
Customer
();
$customerB
=
new
Customer
();
$this
->
assertFalse
(
$customerA
->
equals
(
$customerB
));
$customerA
=
new
Customer
();
$customerB
=
new
Item
();
$this
->
assertFalse
(
$customerA
->
equals
(
$customerB
));
$customerA
=
Customer
::
find
(
1
);
$customerB
=
Customer
::
find
(
2
);
$this
->
assertFalse
(
$customerA
->
equals
(
$customerB
));
$customerB
=
Customer
::
find
(
1
);
$this
->
assertTrue
(
$customerA
->
equals
(
$customerB
));
$customerA
=
Customer
::
find
(
1
);
$customerB
=
Item
::
find
(
1
);
$this
->
assertFalse
(
$customerA
->
equals
(
$customerB
));
}
public
function
testFindCount
()
{
$this
->
assertEquals
(
3
,
Customer
::
find
()
->
count
());
...
...
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