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
f759ee18
Commit
f759ee18
authored
Sep 05, 2013
by
Carsten Brandt
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Elasticsearch WIP
parent
38dab349
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
1055 additions
and
0 deletions
+1055
-0
ActiveQuery.php
framework/yii/db/elasticsearch/ActiveQuery.php
+343
-0
ActiveRecord.php
framework/yii/db/elasticsearch/ActiveRecord.php
+543
-0
Connection.php
framework/yii/db/elasticsearch/Connection.php
+145
-0
Node.php
framework/yii/db/elasticsearch/Node.php
+24
-0
No files found.
framework/yii/db/elasticsearch/ActiveQuery.php
0 → 100644
View file @
f759ee18
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright © 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace
yii\db\elasticsearch
;
/**
* ActiveQuery represents a DB query associated with an Active Record class.
*
*
* @author Carsten Brandt <mail@cebe.cc>
* @since 2.0
*/
class
ActiveQuery
extends
\yii\base\Component
{
/**
* @var string the name of the ActiveRecord class.
*/
public
$modelClass
;
/**
* @var array list of relations that this query should be performed with
*/
public
$with
;
/**
* @var string the name of the column by which query results should be indexed by.
* This is only used when the query result is returned as an array when calling [[all()]].
*/
public
$indexBy
;
/**
* @var boolean whether to return each record as an array. If false (default), an object
* of [[modelClass]] will be created to represent each record.
*/
public
$asArray
;
/**
* @var integer maximum number of records to be returned. If not set or less than 0, it means no limit.
*/
public
$limit
;
/**
* @var integer zero-based offset from where the records are to be returned.
* If not set, it means starting from the beginning.
* If less than zero it means starting n elements from the end.
*/
public
$offset
;
/**
* @var array array of primary keys of the records to find.
*/
public
$primaryKeys
;
/**
* List of multiple pks must be zero based
*
* @param $primaryKeys
* @return ActiveQuery
*/
public
function
primaryKeys
(
$primaryKeys
)
{
if
(
is_array
(
$primaryKeys
)
&&
isset
(
$primaryKeys
[
0
]))
{
$this
->
primaryKeys
=
$primaryKeys
;
}
else
{
$this
->
primaryKeys
=
array
(
$primaryKeys
);
}
return
$this
;
}
/**
* Executes query and returns all results as an array.
* @return array the query results. If the query results in nothing, an empty array will be returned.
*/
public
function
all
()
{
$modelClass
=
$this
->
modelClass
;
/** @var Connection $db */
$db
=
$modelClass
::
getDb
();
if
((
$primaryKeys
=
$this
->
primaryKeys
)
===
null
)
{
$start
=
$this
->
offset
===
null
?
0
:
$this
->
offset
;
$end
=
$this
->
limit
===
null
?
-
1
:
$start
+
$this
->
limit
;
$primaryKeys
=
$db
->
executeCommand
(
'LRANGE'
,
array
(
$modelClass
::
tableName
(),
$start
,
$end
));
}
$rows
=
array
();
foreach
(
$primaryKeys
as
$pk
)
{
$key
=
$modelClass
::
tableName
()
.
':a:'
.
$modelClass
::
hashPk
(
$pk
);
// get attributes
$data
=
$db
->
executeCommand
(
'HGETALL'
,
array
(
$key
));
$row
=
array
();
for
(
$i
=
0
;
$i
<
count
(
$data
);)
{
$row
[
$data
[
$i
++
]]
=
$data
[
$i
++
];
}
$rows
[]
=
$row
;
}
if
(
$rows
!==
array
())
{
$models
=
$this
->
createModels
(
$rows
);
if
(
!
empty
(
$this
->
with
))
{
$this
->
populateRelations
(
$models
,
$this
->
with
);
}
return
$models
;
}
else
{
return
array
();
}
}
/**
* Executes query and returns a single row of result.
* @return ActiveRecord|array|null a single row of query result. Depending on the setting of [[asArray]],
* the query result may be either an array or an ActiveRecord object. Null will be returned
* if the query results in nothing.
*/
public
function
one
()
{
$modelClass
=
$this
->
modelClass
;
/** @var Connection $db */
$db
=
$modelClass
::
getDb
();
if
((
$primaryKeys
=
$this
->
primaryKeys
)
===
null
)
{
$start
=
$this
->
offset
===
null
?
0
:
$this
->
offset
;
$primaryKeys
=
$db
->
executeCommand
(
'LRANGE'
,
array
(
$modelClass
::
tableName
(),
$start
,
$start
+
1
));
}
$pk
=
reset
(
$primaryKeys
);
$key
=
$modelClass
::
tableName
()
.
':a:'
.
$modelClass
::
hashPk
(
$pk
);
// get attributes
$data
=
$db
->
executeCommand
(
'HGETALL'
,
array
(
$key
));
if
(
$data
===
array
())
{
return
null
;
}
$row
=
array
();
for
(
$i
=
0
;
$i
<
count
(
$data
);)
{
$row
[
$data
[
$i
++
]]
=
$data
[
$i
++
];
}
if
(
!
$this
->
asArray
)
{
/** @var $class ActiveRecord */
$class
=
$this
->
modelClass
;
$model
=
$class
::
create
(
$row
);
if
(
!
empty
(
$this
->
with
))
{
$models
=
array
(
$model
);
$this
->
populateRelations
(
$models
,
$this
->
with
);
$model
=
$models
[
0
];
}
return
$model
;
}
else
{
return
$row
;
}
}
/**
* Returns the number of records.
* @param string $q the COUNT expression. Defaults to '*'.
* Make sure you properly quote column names.
* @return integer number of records
*/
public
function
count
()
{
$modelClass
=
$this
->
modelClass
;
/** @var Connection $db */
$db
=
$modelClass
::
getDb
();
return
$db
->
executeCommand
(
'LLEN'
,
array
(
$modelClass
::
tableName
()));
}
/**
* Returns the query result as a scalar value.
* The value returned will be the first column in the first row of the query results.
* @return string|boolean the value of the first column in the first row of the query result.
* False is returned if the query result is empty.
*/
public
function
scalar
(
$column
)
{
$record
=
$this
->
one
();
return
$record
->
$column
;
}
/**
* Returns a value indicating whether the query result contains any row of data.
* @return boolean whether the query result contains any row of data.
*/
public
function
exists
()
{
return
$this
->
one
()
!==
null
;
}
/**
* Sets the [[asArray]] property.
* TODO: refactor, it is duplicated from yii/db/ActiveQuery
* @param boolean $value whether to return the query results in terms of arrays instead of Active Records.
* @return ActiveQuery the query object itself
*/
public
function
asArray
(
$value
=
true
)
{
$this
->
asArray
=
$value
;
return
$this
;
}
/**
* Sets the LIMIT part of the query.
* TODO: refactor, it is duplicated from yii/db/Query
* @param integer $limit the limit
* @return Query the query object itself
*/
public
function
limit
(
$limit
)
{
$this
->
limit
=
$limit
;
return
$this
;
}
/**
* Sets the OFFSET part of the query.
* TODO: refactor, it is duplicated from yii/db/Query
* @param integer $offset the offset
* @return Query the query object itself
*/
public
function
offset
(
$offset
)
{
$this
->
offset
=
$offset
;
return
$this
;
}
/**
* Specifies the relations with which this query should be performed.
*
* The parameters to this method can be either one or multiple strings, or a single array
* of relation names and the optional callbacks to customize the relations.
*
* The followings are some usage examples:
*
* ~~~
* // find customers together with their orders and country
* Customer::find()->with('orders', 'country')->all();
* // find customers together with their country and orders of status 1
* Customer::find()->with(array(
* 'orders' => function($query) {
* $query->andWhere('status = 1');
* },
* 'country',
* ))->all();
* ~~~
*
* TODO: refactor, it is duplicated from yii/db/ActiveQuery
* @return ActiveQuery the query object itself
*/
public
function
with
()
{
$this
->
with
=
func_get_args
();
if
(
isset
(
$this
->
with
[
0
])
&&
is_array
(
$this
->
with
[
0
]))
{
// the parameter is given as an array
$this
->
with
=
$this
->
with
[
0
];
}
return
$this
;
}
/**
* Sets the [[indexBy]] property.
* TODO: refactor, it is duplicated from yii/db/ActiveQuery
* @param string $column the name of the column by which the query results should be indexed by.
* @return ActiveQuery the query object itself
*/
public
function
indexBy
(
$column
)
{
$this
->
indexBy
=
$column
;
return
$this
;
}
// TODO: refactor, it is duplicated from yii/db/ActiveQuery
private
function
createModels
(
$rows
)
{
$models
=
array
();
if
(
$this
->
asArray
)
{
if
(
$this
->
indexBy
===
null
)
{
return
$rows
;
}
foreach
(
$rows
as
$row
)
{
$models
[
$row
[
$this
->
indexBy
]]
=
$row
;
}
}
else
{
/** @var $class ActiveRecord */
$class
=
$this
->
modelClass
;
if
(
$this
->
indexBy
===
null
)
{
foreach
(
$rows
as
$row
)
{
$models
[]
=
$class
::
create
(
$row
);
}
}
else
{
foreach
(
$rows
as
$row
)
{
$model
=
$class
::
create
(
$row
);
$models
[
$model
->
{
$this
->
indexBy
}]
=
$model
;
}
}
}
return
$models
;
}
// TODO: refactor, it is duplicated from yii/db/ActiveQuery
private
function
populateRelations
(
&
$models
,
$with
)
{
$primaryModel
=
new
$this
->
modelClass
;
$relations
=
$this
->
normalizeRelations
(
$primaryModel
,
$with
);
foreach
(
$relations
as
$name
=>
$relation
)
{
if
(
$relation
->
asArray
===
null
)
{
// inherit asArray from primary query
$relation
->
asArray
=
$this
->
asArray
;
}
$relation
->
findWith
(
$name
,
$models
);
}
}
/**
* TODO: refactor, it is duplicated from yii/db/ActiveQuery
* @param ActiveRecord $model
* @param array $with
* @return ActiveRelation[]
*/
private
function
normalizeRelations
(
$model
,
$with
)
{
$relations
=
array
();
foreach
(
$with
as
$name
=>
$callback
)
{
if
(
is_integer
(
$name
))
{
$name
=
$callback
;
$callback
=
null
;
}
if
((
$pos
=
strpos
(
$name
,
'.'
))
!==
false
)
{
// with sub-relations
$childName
=
substr
(
$name
,
$pos
+
1
);
$name
=
substr
(
$name
,
0
,
$pos
);
}
else
{
$childName
=
null
;
}
$t
=
strtolower
(
$name
);
if
(
!
isset
(
$relations
[
$t
]))
{
$relation
=
$model
->
getRelation
(
$name
);
$relation
->
primaryModel
=
null
;
$relations
[
$t
]
=
$relation
;
}
else
{
$relation
=
$relations
[
$t
];
}
if
(
isset
(
$childName
))
{
$relation
->
with
[
$childName
]
=
$callback
;
}
elseif
(
$callback
!==
null
)
{
call_user_func
(
$callback
,
$relation
);
}
}
return
$relations
;
}
}
framework/yii/db/elasticsearch/ActiveRecord.php
0 → 100644
View file @
f759ee18
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright © 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace
yii\db\elasticsearch
;
use
yii\base\InvalidCallException
;
use
yii\base\InvalidConfigException
;
use
yii\base\InvalidParamException
;
use
yii\base\NotSupportedException
;
use
yii\base\UnknownMethodException
;
use
yii\db\TableSchema
;
/**
* ActiveRecord is the base class for classes representing relational data in terms of objects.
*
*
*
* @author Carsten Brandt <mail@cebe.cc>
* @since 2.0
*/
abstract
class
ActiveRecord
extends
\yii\db\ActiveRecord
{
/**
* Returns the database connection used by this AR class.
* By default, the "elasticsearch" application component is used as the database connection.
* You may override this method if you want to use a different database connection.
* @return Connection the database connection used by this AR class.
*/
public
static
function
getDb
()
{
return
\Yii
::
$app
->
elasticsearch
;
}
public
static
function
primaryKey
()
{
return
array
(
'id'
);
}
/**
* Creates an [[ActiveQuery]] instance for query purpose.
*
* @include @yii/db/ActiveRecord-find.md
*
* @param mixed $q the query parameter. This can be one of the followings:
*
* - a scalar value (integer or string): query by a single primary key value and return the
* corresponding record.
* - 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|ActiveRecord|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).
* @see createQuery()
*/
public
static
function
find
(
$q
=
null
)
// TODO optimize API
{
$query
=
static
::
createQuery
();
if
(
is_array
(
$q
))
{
return
$query
->
primaryKeys
(
$q
)
->
one
();
}
elseif
(
$q
!==
null
)
{
// query by primary key
$primaryKey
=
static
::
primaryKey
();
return
$query
->
primaryKeys
(
array
(
$primaryKey
[
0
]
=>
$q
))
->
one
();
}
return
$query
;
}
/**
* @inheritdoc
*/
public
static
function
findBySql
(
$sql
,
$params
=
array
())
{
throw
new
NotSupportedException
(
'findBySql() is not supported by elasticsearch ActiveRecord'
);
}
/**
* Creates an [[ActiveQuery]] instance.
* This method is called by [[find()]], [[findBySql()]] and [[count()]] to start a SELECT query.
* You may override this method to return a customized query (e.g. `CustomerQuery` specified
* written for querying `Customer` purpose.)
* @return ActiveQuery the newly created [[ActiveQuery]] instance.
*/
public
static
function
createQuery
()
{
return
new
ActiveQuery
(
array
(
'modelClass'
=>
get_called_class
(),
));
}
/**
* Declares the name of the database table associated with this AR class.
* @return string the table name
*/
public
static
function
tableName
()
{
return
static
::
getTableSchema
()
->
name
;
}
public
static
function
indexName
()
{
return
static
::
getTableSchema
()
->
name
;
}
/**
* Returns the schema information of the DB table associated with this AR class.
* @return TableSchema the schema information of the DB table associated with this AR class.
*/
public
static
function
getTableSchema
()
{
// TODO should be cached
throw
new
InvalidConfigException
(
__CLASS__
.
'::getTableSchema() needs to be overridden in subclasses and return a TableSchema.'
);
}
/**
* Inserts a row into the associated database table 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 [[changedAttributes|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.
*
* 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 that are loaded from DB will be saved.
* @return boolean whether the attributes are valid and the record is inserted successfully.
*/
public
function
insert
(
$runValidation
=
true
,
$attributes
=
null
)
{
if
(
$runValidation
&&
!
$this
->
validate
(
$attributes
))
{
return
false
;
}
if
(
$this
->
beforeSave
(
true
))
{
$db
=
static
::
getDb
();
$values
=
$this
->
getDirtyAttributes
(
$attributes
);
$pk
=
array
();
foreach
(
$this
->
primaryKey
()
as
$key
)
{
$pk
[
$key
]
=
$values
[
$key
]
=
$this
->
getAttribute
(
$key
);
if
(
$pk
[
$key
]
===
null
)
{
$pk
[
$key
]
=
$values
[
$key
]
=
0
;
// TODO add support for incrementing PK
$this
->
setAttribute
(
$key
,
$values
[
$key
]);
}
}
// TODO store record in index
$this
->
setOldAttributes
(
$values
);
$this
->
afterSave
(
true
);
return
true
;
}
return
false
;
}
/**
* Updates the whole table using the provided attribute values and conditions.
* For example, to change the status to be 1 for all customers whose status is 2:
*
* ~~~
* Customer::updateAll(array('status' => 1), 'status = 2');
* ~~~
*
* @param array $attributes attribute values (name-value pairs) to be saved into the table
* @param string|array $condition the conditions that will be put in the WHERE part of the UPDATE SQL.
* Please refer to [[Query::where()]] on how to specify this parameter.
* @param array $params the parameters (name=>value) to be bound to the query.
* @return integer the number of rows updated
*/
public
static
function
updateAll
(
$attributes
,
$condition
=
''
,
$params
=
array
())
{
$db
=
static
::
getDb
();
// TODO massive update (do a find and then update each record)
if
(
empty
(
$attributes
))
{
return
0
;
}
$n
=
0
;
// foreach(... as $pk) {
//
// // TODO update records
//
// $n++;
// }
return
$n
;
}
/**
* Updates the whole table using the provided counter changes and conditions.
* For example, to increment all customers' age by 1,
*
* ~~~
* Customer::updateAllCounters(array('age' => 1));
* ~~~
*
* @param array $counters the counters to be updated (attribute name => increment value).
* Use negative values if you want to decrement the counters.
* @param string|array $condition the conditions that will be put in the WHERE part of the UPDATE SQL.
* Please refer to [[Query::where()]] on how to specify this parameter.
* @param array $params the parameters (name=>value) to be bound to the query.
* Do not name the parameters as `:bp0`, `:bp1`, etc., because they are used internally by this method.
* @return integer the number of rows updated
*/
public
static
function
updateAllCounters
(
$counters
,
$condition
=
''
,
$params
=
array
())
{
// TODO implement
throw
new
NotSupportedException
(
'update counters is not supported by elasticsearch.'
);
}
/**
* Deletes rows in the table using the provided conditions.
* WARNING: If you do not specify any condition, this method will delete ALL rows in the table.
*
* For example, to delete all customers whose status is 3:
*
* ~~~
* Customer::deleteAll('status = 3');
* ~~~
*
* @param string|array $condition the conditions that will be put in the WHERE part of the DELETE SQL.
* Please refer to [[Query::where()]] on how to specify this parameter.
* @param array $params the parameters (name=>value) to be bound to the query.
* @return integer the number of rows deleted
*/
public
static
function
deleteAll
(
$condition
=
''
,
$params
=
array
())
{
$db
=
static
::
getDb
();
// TODO massive delete (do a find and then delete each record)
if
(
empty
(
$condition
))
{
return
0
;
}
$n
=
0
;
// foreach($condition as $pk) {
//
// $n++;
// }
return
$n
;
}
/**
* Declares a `has-one` relation.
* The declaration is returned in terms of an [[ActiveRelation]] instance
* through which the related record can be queried and retrieved back.
*
* A `has-one` relation means that there is at most one related record matching
* the criteria set by this relation, e.g., a customer has one country.
*
* For example, to declare the `country` relation for `Customer` class, we can write
* the following code in the `Customer` class:
*
* ~~~
* public function getCountry()
* {
* return $this->hasOne('Country', array('id' => 'country_id'));
* }
* ~~~
*
* Note that in the above, the 'id' key in the `$link` parameter refers to an attribute name
* in the related class `Country`, while the 'country_id' value refers to an attribute name
* in the current AR class.
*
* Call methods declared in [[ActiveRelation]] to further customize the relation.
*
* @param string $class the class name of the related record
* @param array $link the primary-foreign key constraint. The keys of the array refer to
* the columns in the table associated with the `$class` model, while the values of the
* array refer to the corresponding columns in the table associated with this AR class.
* @return ActiveRelation the relation object.
*/
public
function
hasOne
(
$class
,
$link
)
{
return
new
ActiveRelation
(
array
(
'modelClass'
=>
$this
->
getNamespacedClass
(
$class
),
'primaryModel'
=>
$this
,
'link'
=>
$link
,
'multiple'
=>
false
,
));
}
/**
* Declares a `has-many` relation.
* The declaration is returned in terms of an [[ActiveRelation]] instance
* through which the related record can be queried and retrieved back.
*
* A `has-many` relation means that there are multiple related records matching
* the criteria set by this relation, e.g., a customer has many orders.
*
* For example, to declare the `orders` relation for `Customer` class, we can write
* the following code in the `Customer` class:
*
* ~~~
* public function getOrders()
* {
* return $this->hasMany('Order', array('customer_id' => 'id'));
* }
* ~~~
*
* Note that in the above, the 'customer_id' key in the `$link` parameter refers to
* an attribute name in the related class `Order`, while the 'id' value refers to
* an attribute name in the current AR class.
*
* @param string $class the class name of the related record
* @param array $link the primary-foreign key constraint. The keys of the array refer to
* the columns in the table associated with the `$class` model, while the values of the
* array refer to the corresponding columns in the table associated with this AR class.
* @return ActiveRelation the relation object.
*/
public
function
hasMany
(
$class
,
$link
)
{
return
new
ActiveRelation
(
array
(
'modelClass'
=>
$this
->
getNamespacedClass
(
$class
),
'primaryModel'
=>
$this
,
'link'
=>
$link
,
'multiple'
=>
true
,
));
}
/**
* Returns the relation object with the specified name.
* A relation is defined by a getter method which returns an [[ActiveRelation]] object.
* It can be declared in either the Active Record class itself or one of its behaviors.
* @param string $name the relation name
* @return ActiveRelation the relation object
* @throws InvalidParamException if the named relation does not exist.
*/
public
function
getRelation
(
$name
)
{
$getter
=
'get'
.
$name
;
try
{
$relation
=
$this
->
$getter
();
if
(
$relation
instanceof
ActiveRelation
)
{
return
$relation
;
}
}
catch
(
UnknownMethodException
$e
)
{
}
throw
new
InvalidParamException
(
get_class
(
$this
)
.
' has no relation named "'
.
$name
.
'".'
);
}
/**
* Establishes the relationship between two models.
*
* The relationship is established by setting the foreign key value(s) in one model
* to be the corresponding primary key value(s) in the other model.
* The model with the foreign key will be saved into database without performing validation.
*
* If the relationship involves a pivot table, a new row will be inserted into the
* pivot table which contains the primary key values from both models.
*
* Note that this method requires that the primary key value is not null.
*
* @param string $name the name of the relationship
* @param ActiveRecord $model the model to be linked with the current one.
* @param array $extraColumns additional column values to be saved into the pivot table.
* This parameter is only meaningful for a relationship involving a pivot table
* (i.e., a relation set with `[[ActiveRelation::via()]]` or `[[ActiveRelation::viaTable()]]`.)
* @throws InvalidCallException if the method is unable to link two models.
*/
public
function
link
(
$name
,
$model
,
$extraColumns
=
array
())
{
$relation
=
$this
->
getRelation
(
$name
);
if
(
$relation
->
via
!==
null
)
{
// TODO
}
else
{
$p1
=
$model
->
isPrimaryKey
(
array_keys
(
$relation
->
link
));
$p2
=
$this
->
isPrimaryKey
(
array_values
(
$relation
->
link
));
if
(
$p1
&&
$p2
)
{
if
(
$this
->
getIsNewRecord
()
&&
$model
->
getIsNewRecord
())
{
throw
new
InvalidCallException
(
'Unable to link models: both models are newly created.'
);
}
elseif
(
$this
->
getIsNewRecord
())
{
$this
->
bindModels
(
array_flip
(
$relation
->
link
),
$this
,
$model
);
}
else
{
$this
->
bindModels
(
$relation
->
link
,
$model
,
$this
);
}
}
elseif
(
$p1
)
{
$this
->
bindModels
(
array_flip
(
$relation
->
link
),
$this
,
$model
);
}
elseif
(
$p2
)
{
$this
->
bindModels
(
$relation
->
link
,
$model
,
$this
);
}
else
{
throw
new
InvalidCallException
(
'Unable to link models: the link does not involve any primary key.'
);
}
}
// update lazily loaded related objects
if
(
!
$relation
->
multiple
)
{
$this
->
_related
[
$name
]
=
$model
;
}
elseif
(
isset
(
$this
->
_related
[
$name
]))
{
if
(
$relation
->
indexBy
!==
null
)
{
$indexBy
=
$relation
->
indexBy
;
$this
->
_related
[
$name
][
$model
->
$indexBy
]
=
$model
;
}
else
{
$this
->
_related
[
$name
][]
=
$model
;
}
}
}
/**
* @param array $link
* @param ActiveRecord $foreignModel
* @param ActiveRecord $primaryModel
* @throws InvalidCallException
*/
private
function
bindModels
(
$link
,
$foreignModel
,
$primaryModel
)
{
foreach
(
$link
as
$fk
=>
$pk
)
{
$value
=
$primaryModel
->
$pk
;
if
(
$value
===
null
)
{
throw
new
InvalidCallException
(
'Unable to link models: the primary key of '
.
get_class
(
$primaryModel
)
.
' is null.'
);
}
$foreignModel
->
$fk
=
$value
;
}
$foreignModel
->
save
(
false
);
}
/**
* Destroys the relationship between two models.
*
* The model with the foreign key of the relationship will be deleted if `$delete` is true.
* Otherwise, the foreign key will be set null and the model will be saved without validation.
*
* @param string $name the name of the relationship.
* @param ActiveRecord $model the model to be unlinked from the current one.
* @param boolean $delete whether to delete the model that contains the foreign key.
* If false, the model's foreign key will be set null and saved.
* If true, the model containing the foreign key will be deleted.
* @throws InvalidCallException if the models cannot be unlinked
*/
public
function
unlink
(
$name
,
$model
,
$delete
=
false
)
{
// TODO
$relation
=
$this
->
getRelation
(
$name
);
if
(
$relation
->
via
!==
null
)
{
if
(
is_array
(
$relation
->
via
))
{
/** @var $viaRelation ActiveRelation */
list
(
$viaName
,
$viaRelation
)
=
$relation
->
via
;
/** @var $viaClass ActiveRecord */
$viaClass
=
$viaRelation
->
modelClass
;
$viaTable
=
$viaClass
::
tableName
();
unset
(
$this
->
_related
[
strtolower
(
$viaName
)]);
}
else
{
$viaRelation
=
$relation
->
via
;
$viaTable
=
reset
(
$relation
->
via
->
from
);
}
$columns
=
array
();
foreach
(
$viaRelation
->
link
as
$a
=>
$b
)
{
$columns
[
$a
]
=
$this
->
$b
;
}
foreach
(
$relation
->
link
as
$a
=>
$b
)
{
$columns
[
$b
]
=
$model
->
$a
;
}
$command
=
static
::
getDb
()
->
createCommand
();
if
(
$delete
)
{
$command
->
delete
(
$viaTable
,
$columns
)
->
execute
();
}
else
{
$nulls
=
array
();
foreach
(
array_keys
(
$columns
)
as
$a
)
{
$nulls
[
$a
]
=
null
;
}
$command
->
update
(
$viaTable
,
$nulls
,
$columns
)
->
execute
();
}
}
else
{
$p1
=
$model
->
isPrimaryKey
(
array_keys
(
$relation
->
link
));
$p2
=
$this
->
isPrimaryKey
(
array_values
(
$relation
->
link
));
if
(
$p1
&&
$p2
||
$p2
)
{
foreach
(
$relation
->
link
as
$a
=>
$b
)
{
$model
->
$a
=
null
;
}
$delete
?
$model
->
delete
()
:
$model
->
save
(
false
);
}
elseif
(
$p1
)
{
foreach
(
$relation
->
link
as
$b
)
{
$this
->
$b
=
null
;
}
$delete
?
$this
->
delete
()
:
$this
->
save
(
false
);
}
else
{
throw
new
InvalidCallException
(
'Unable to unlink models: the link does not involve any primary key.'
);
}
}
if
(
!
$relation
->
multiple
)
{
unset
(
$this
->
_related
[
$name
]);
}
elseif
(
isset
(
$this
->
_related
[
$name
]))
{
/** @var $b ActiveRecord */
foreach
(
$this
->
_related
[
$name
]
as
$a
=>
$b
)
{
if
(
$model
->
getPrimaryKey
()
==
$b
->
getPrimaryKey
())
{
unset
(
$this
->
_related
[
$name
][
$a
]);
}
}
}
}
/**
* TODO duplicate code, refactor
* @param array $keys
* @return boolean
*/
private
function
isPrimaryKey
(
$keys
)
{
$pks
=
$this
->
primaryKey
();
foreach
(
$keys
as
$key
)
{
if
(
!
in_array
(
$key
,
$pks
,
true
))
{
return
false
;
}
}
return
true
;
}
// TODO implement link and unlink
}
framework/yii/db/elasticsearch/Connection.php
0 → 100644
View file @
f759ee18
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright © 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace
yii\db\elasticsearch
;
use
yii\base\Component
;
use
yii\base\InvalidConfigException
;
/**
*
* @author Carsten Brandt <mail@cebe.cc>
* @since 2.0
*/
class
Connection
extends
Component
{
/**
* @event Event an event that is triggered after a DB connection is established
*/
const
EVENT_AFTER_OPEN
=
'afterOpen'
;
// TODO add autodetection of cluster nodes
public
$nodes
=
array
();
// TODO use timeouts
/**
* @var float timeout to use for connection to redis. If not set the timeout set in php.ini will be used: ini_get("default_socket_timeout")
*/
public
$connectionTimeout
=
null
;
/**
* @var float timeout to use for redis socket when reading and writing data. If not set the php default value will be used.
*/
public
$dataTimeout
=
null
;
public
function
init
()
{
if
(
$this
->
nodes
===
array
())
{
throw
new
InvalidConfigException
(
'elasticsearch needs at least one node.'
);
}
}
/**
* Closes the connection when this component is being serialized.
* @return array
*/
public
function
__sleep
()
{
$this
->
close
();
return
array_keys
(
get_object_vars
(
$this
));
}
/**
* Returns a value indicating whether the DB connection is established.
* @return boolean whether the DB connection is established
*/
public
function
getIsActive
()
{
return
false
;
// TODO implement
}
/**
* Establishes a DB connection.
* It does nothing if a DB connection has already been established.
* @throws Exception if connection fails
*/
public
function
open
()
{
/* if ($this->_socket === null) {
if (empty($this->dsn)) {
throw new InvalidConfigException('Connection.dsn cannot be empty.');
}
$dsn = explode('/', $this->dsn);
$host = $dsn[2];
if (strpos($host, ':')===false) {
$host .= ':6379';
}
$db = isset($dsn[3]) ? $dsn[3] : 0;
\Yii::trace('Opening DB connection: ' . $this->dsn, __CLASS__);
$this->_socket = @stream_socket_client(
$host,
$errorNumber,
$errorDescription,
$this->connectionTimeout ? $this->connectionTimeout : ini_get("default_socket_timeout")
);
if ($this->_socket) {
if ($this->dataTimeout !== null) {
stream_set_timeout($this->_socket, $timeout=(int)$this->dataTimeout, (int) (($this->dataTimeout - $timeout) * 1000000));
}
if ($this->password !== null) {
$this->executeCommand('AUTH', array($this->password));
}
$this->executeCommand('SELECT', array($db));
$this->initConnection();
} else {
\Yii::error("Failed to open DB connection ({$this->dsn}): " . $errorNumber . ' - ' . $errorDescription, __CLASS__);
$message = YII_DEBUG ? 'Failed to open DB connection: ' . $errorNumber . ' - ' . $errorDescription : 'Failed to open DB connection.';
throw new Exception($message, $errorDescription, (int)$errorNumber);
}
}*/
// TODO implement
}
/**
* Closes the currently active DB connection.
* It does nothing if the connection is already closed.
*/
public
function
close
()
{
// TODO implement
/* if ($this->_socket !== null) {
\Yii::trace('Closing DB connection: ' . $this->dsn, __CLASS__);
$this->executeCommand('QUIT');
stream_socket_shutdown($this->_socket, STREAM_SHUT_RDWR);
$this->_socket = null;
$this->_transaction = null;
}*/
}
/**
* Initializes the DB connection.
* This method is invoked right after the DB connection is established.
* The default implementation triggers an [[EVENT_AFTER_OPEN]] event.
*/
protected
function
initConnection
()
{
$this
->
trigger
(
self
::
EVENT_AFTER_OPEN
);
}
/**
* Returns the name of the DB driver for the current [[dsn]].
* @return string name of the DB driver
*/
public
function
getDriverName
()
{
return
'elasticsearch'
;
}
}
\ No newline at end of file
framework/yii/db/elasticsearch/Node.php
0 → 100644
View file @
f759ee18
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright © 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace
yii\db\elasticsearch
;
use
yii\base\Object
;
/**
* Represents an elastic search cluster node.
*
* @author Carsten Brandt <mail@cebe.cc>
* @since 2.0
*/
class
Node
extends
Object
{
public
$host
;
public
$port
;
}
\ No newline at end of file
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