Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
project
drupal
Commits
4ea00421
Commit
4ea00421
authored
Aug 28, 2012
by
bojanz
Committed by
tim.plunkett
Oct 21, 2012
Browse files
Issue
#1758634
by bojanz: The query plugin should load entities after the query has been executed.
parent
1f4c2c16
Changes
8
Hide whitespace changes
Inline
Side-by-side
lib/Drupal/views/Plugin/views/field/Entity.php
deleted
100644 → 0
View file @
1f4c2c16
<?php
/**
* @file
* Definition of Drupal\views\Plugin\views\field\Entity.
*/
namespace
Drupal\views\Plugin\views\field
;
use
Drupal\Core\Annotation\Plugin
;
/**
* A handler to display data from entity objects.
*
* Fields based upon this handler work with all query-backends if the tables
* used by the query backend have an 'entity type' specified. In order to
* make fields based upon this handler automatically available to all compatible
* query backends, the views field can be defined in the table
* @code views_entity_{ENTITY_TYPE} @endcode.
*
* @ingroup views_field_handlers
*
* @Plugin(
* id = "entity"
* )
*/
class
Entity
extends
FieldPluginBase
{
/**
* Stores the entity type which is loaded by this field.
*/
public
$entity_type
;
/**
* Stores all entites which are in the result.
*/
public
$entities
;
/**
* The base field of the entity type assosiated with this field.
*/
public
$base_field
;
/**
* Initialize the entity type.
*/
public
function
init
(
&
$view
,
&
$options
)
{
parent
::
init
(
$view
,
$options
);
// Initialize the entity-type used.
$table_data
=
views_fetch_data
(
$this
->
table
);
$this
->
entity_type
=
$table_data
[
'table'
][
'entity type'
];
}
/**
* Overriden to add the field for the entity id.
*/
function
query
()
{
$this
->
table_alias
=
$base_table
=
$this
->
view
->
base_table
;
$this
->
base_field
=
$this
->
view
->
base_field
;
if
(
!
empty
(
$this
->
relationship
))
{
foreach
(
$this
->
view
->
relationship
as
$relationship
)
{
if
(
$relationship
->
alias
==
$this
->
relationship
)
{
$base_table
=
$relationship
->
definition
[
'base'
];
$this
->
table_alias
=
$relationship
->
alias
;
$table_data
=
views_fetch_data
(
$base_table
);
$this
->
base_field
=
empty
(
$relationship
->
definition
[
'base field'
])
?
$table_data
[
'table'
][
'base'
][
'field'
]
:
$relationship
->
definition
[
'base field'
];
}
}
}
// Add the field if the query back-end implements an add_field() method,
// just like the default back-end.
if
(
method_exists
(
$this
->
query
,
'add_field'
))
{
$this
->
field_alias
=
$this
->
query
->
add_field
(
$this
->
table_alias
,
$this
->
base_field
,
''
);
}
$this
->
add_additional_fields
();
}
/**
* Load the entities for all rows that are about to be displayed.
*/
function
pre_render
(
&
$values
)
{
if
(
!
empty
(
$values
))
{
list
(
$this
->
entity_type
,
$this
->
entities
)
=
$this
->
query
->
get_result_entities
(
$values
,
!
empty
(
$this
->
relationship
)
?
$this
->
relationship
:
NULL
,
$this
->
field_alias
);
}
}
/**
* Overridden to return the entity object, or a certain property of the entity.
*/
function
get_value
(
$values
,
$field
=
NULL
)
{
if
(
isset
(
$this
->
entities
[
$this
->
view
->
row_index
]))
{
$entity
=
$this
->
entities
[
$this
->
view
->
row_index
];
// Support to get a certain part of the entity.
if
(
isset
(
$field
)
&&
isset
(
$entity
->
{
$field
}))
{
return
$entity
->
{
$field
};
}
// Support to get a part of the values as the normal get_value.
elseif
(
isset
(
$field
)
&&
isset
(
$values
->
{
$this
->
aliases
[
$field
]}))
{
return
$values
->
{
$this
->
aliases
[
$field
]};
}
else
{
return
$entity
;
}
}
return
FALSE
;
}
}
lib/Drupal/views/Plugin/views/field/FieldPluginBase.php
View file @
4ea00421
...
...
@@ -362,6 +362,22 @@ function element_wrapper_classes($row_index = NULL) {
return
implode
(
' '
,
$classes
);
}
/**
* Get the entity matching the current row and relationship.
*
* @param $values
* An object containing all retrieved values.
*/
function
get_entity
(
$values
)
{
$relationship_id
=
$this
->
options
[
'relationship'
];
if
(
$relationship_id
==
'none'
)
{
return
$values
->
_entity
;
}
else
{
return
$values
->
_relationship_entities
[
$relationship_id
];
}
}
/**
* Get the value that's supposed to be rendered.
*
...
...
lib/Drupal/views/Plugin/views/query/QueryPluginBase.php
View file @
4ea00421
...
...
@@ -158,10 +158,14 @@ function set_group_operator($type = 'AND') {
}
/**
* Returns the according entity objects for the given query results.
* Loads all entities contained in the passed-in $results.
*.
* If the entity belongs to the base table, then it gets stored in
* $result->_entity. Otherwise, it gets stored in
* $result->_relationship_entities[$relationship_id];
*
* Query plugins that don't support entities can leave the method empty.
*/
function
get_result_entities
(
$results
,
$relationship
=
NULL
)
{
return
FALSE
;
}
function
load_entities
(
&
$results
)
{}
}
lib/Drupal/views/Plugin/views/query/Sql.php
View file @
4ea00421
...
...
@@ -1316,6 +1316,25 @@ function query($get_count = FALSE) {
$groupby
=
array_unique
(
array_merge
(
$this
->
groupby
,
$non_aggregates
));
}
// Make sure each entity table has the base field added so that the
// entities can be loaded.
$entity_tables
=
$this
->
get_entity_tables
();
if
(
$entity_tables
)
{
$params
=
array
();
if
(
$groupby
)
{
// Handle grouping, by retrieving the minimum entity_id.
$params
=
array
(
'function'
=>
'min'
,
);
}
foreach
(
$entity_tables
as
$table_alias
=>
$table
)
{
$info
=
entity_get_info
(
$table
[
'entity_type'
]);
$base_field
=
empty
(
$table
[
'revision'
])
?
$info
[
'entity keys'
][
'id'
]
:
$info
[
'entity keys'
][
'revision'
];
$this
->
add_field
(
$table_alias
,
$base_field
,
''
,
$params
);
}
}
// Add all fields to the query.
$this
->
compile_fields
(
$query
);
...
...
@@ -1486,6 +1505,9 @@ function execute(&$view) {
if
(
$view
->
pager
->
use_count_query
()
||
!
empty
(
$view
->
get_total_rows
))
{
$view
->
total_rows
=
$view
->
pager
->
get_total_items
();
}
// Load all entities contained in the results.
$this
->
load_entities
(
$view
->
result
);
}
catch
(
DatabaseExceptionWrapper
$e
)
{
$view
->
result
=
array
();
...
...
@@ -1504,6 +1526,125 @@ function execute(&$view) {
$view
->
execute_time
=
microtime
(
TRUE
)
-
$start
;
}
/**
* Returns an array of all tables from the query that map to an entity type.
*
* Includes the base table and all relationships, if eligible.
* Available keys for each table:
* - base: The actual base table (i.e. "user" for an author relationship).
* - relationship_id: The id of the relationship, or "none".
* - entity_type: The entity type matching the base table.
* - revision: A boolean that specifies whether the table is a base table or
* a revision table of the entity type.
*
* @return array
* An array of table information, keyed by table alias.
*/
function
get_entity_tables
()
{
// Start with the base table.
$entity_tables
=
array
();
$base_table_data
=
views_fetch_data
(
$this
->
base_table
);
if
(
isset
(
$base_table_data
[
'table'
][
'entity type'
]))
{
$entity_tables
[
$this
->
base_table
]
=
array
(
'base'
=>
$this
->
base_table
,
'relationship_id'
=>
'none'
,
'entity_type'
=>
$base_table_data
[
'table'
][
'entity type'
],
'revision'
=>
FALSE
,
);
}
// Include all relationships.
foreach
(
$this
->
view
->
relationship
as
$relationship_id
=>
$relationship
)
{
$table_data
=
views_fetch_data
(
$relationship
->
definition
[
'base'
]);
if
(
isset
(
$table_data
[
'table'
][
'entity type'
]))
{
$entity_tables
[
$relationship
->
alias
]
=
array
(
'base'
=>
$relationship
->
definition
[
'base'
],
'relationship_id'
=>
$relationship_id
,
'entity_type'
=>
$table_data
[
'table'
][
'entity type'
],
'revision'
=>
FALSE
,
);
}
}
// Determine which of the tables are revision tables.
foreach
(
$entity_tables
as
$table_alias
=>
$table
)
{
$info
=
entity_get_info
(
$table
[
'entity_type'
]);
if
(
isset
(
$info
[
'revision table'
])
&&
$info
[
'revision table'
]
==
$table
[
'base'
])
{
$entity_tables
[
$table_alias
][
'revision'
]
=
TRUE
;
}
}
return
$entity_tables
;
}
/**
* Loads all entities contained in the passed-in $results.
*.
* If the entity belongs to the base table, then it gets stored in
* $result->_entity. Otherwise, it gets stored in
* $result->_relationship_entities[$relationship_id];
*/
function
load_entities
(
&
$results
)
{
$entity_tables
=
$this
->
get_entity_tables
();
// No entity tables found, nothing else to do here.
if
(
empty
(
$entity_tables
))
{
return
;
}
// Initialize the entity placeholders in $results.
foreach
(
$results
as
$index
=>
$result
)
{
$results
[
$index
]
->
_entity
=
FALSE
;
$results
[
$index
]
->
_relationship_entities
=
array
();
}
// Assemble a list of entities to load.
$ids_by_table
=
array
();
foreach
(
$entity_tables
as
$table_alias
=>
$table
)
{
$entity_type
=
$table
[
'entity_type'
];
$info
=
entity_get_info
(
$entity_type
);
$id_key
=
empty
(
$table
[
'revision'
])
?
$info
[
'entity keys'
][
'id'
]
:
$info
[
'entity keys'
][
'revision'
];
$id_alias
=
$this
->
get_field_alias
(
$table_alias
,
$id_key
);
foreach
(
$results
as
$index
=>
$result
)
{
// Store the entity id if it was found.
if
(
!
empty
(
$result
->
$id_alias
))
{
$ids_by_table
[
$table_alias
][
$index
]
=
$result
->
$id_alias
;
}
}
}
// Load all entities and assign them to the correct result row.
foreach
(
$ids_by_table
as
$table_alias
=>
$ids
)
{
$table
=
$entity_tables
[
$table_alias
];
$entity_type
=
$table
[
'entity_type'
];
$relationship_id
=
$table
[
'relationship_id'
];
// Drupal core currently has no way to load multiple revisions. Sad.
if
(
$table
[
'revision'
])
{
$entities
=
array
();
foreach
(
$ids
as
$index
=>
$revision_id
)
{
$entity
=
entity_revision_load
(
$entity_type
,
$revision_id
);
if
(
$entity
)
{
$entities
[
$revision_id
]
=
$entity
;
}
}
}
else
{
$entities
=
entity_load_multiple
(
$entity_type
,
$ids
);
}
foreach
(
$ids
as
$index
=>
$id
)
{
$entity
=
isset
(
$entities
[
$id
])
?
$entities
[
$id
]
:
FALSE
;
if
(
$relationship_id
==
'none'
)
{
$results
[
$index
]
->
_entity
=
$entity
;
}
else
{
$results
[
$index
]
->
_relationship_entities
[
$relationship_id
]
=
$entity
;
}
}
}
}
function
add_signature
(
&
$view
)
{
$view
->
query
->
add_field
(
NULL
,
"'"
.
$view
->
name
.
':'
.
$view
->
current_display
.
"'"
,
'view_name'
);
}
...
...
@@ -1589,50 +1730,6 @@ function get_aggregation_info() {
);
}
/**
* Returns the according entity objects for the given query results.
*
*/
function
get_result_entities
(
$results
,
$relationship
=
NULL
)
{
$base_table
=
$this
->
base_table
;
$base_table_alias
=
$base_table
;
if
(
!
empty
(
$relationship
))
{
foreach
(
$this
->
view
->
relationship
as
$current
)
{
if
(
$current
->
alias
==
$relationship
)
{
$base_table
=
$current
->
definition
[
'base'
];
$base_table_alias
=
$relationship
;
break
;
}
}
}
$table_data
=
views_fetch_data
(
$base_table
);
// Bail out if the table has not specified the according entity-type.
if
(
!
isset
(
$table_data
[
'table'
][
'entity type'
]))
{
return
FALSE
;
}
$entity_type
=
$table_data
[
'table'
][
'entity type'
];
$info
=
entity_get_info
(
$entity_type
);
$id_alias
=
$this
->
get_field_alias
(
$base_table_alias
,
$info
[
'entity keys'
][
'id'
]);
// Assemble the ids of the entities to load.
$ids
=
array
();
foreach
(
$results
as
$key
=>
$result
)
{
if
(
isset
(
$result
->
$id_alias
))
{
$ids
[
$key
]
=
$result
->
$id_alias
;
}
}
$entities
=
entity_load_multiple
(
$entity_type
,
$ids
);
// Re-key the array by row-index.
$result
=
array
();
foreach
(
$ids
as
$key
=>
$id
)
{
$result
[
$key
]
=
isset
(
$entities
[
$id
])
?
$entities
[
$id
]
:
FALSE
;
}
return
array
(
$entity_type
,
$result
);
}
function
aggregation_method_simple
(
$group_type
,
$field
)
{
return
strtoupper
(
$group_type
)
.
'('
.
$field
.
')'
;
}
...
...
lib/Views/comment/Plugin/views/field/Link.php
View file @
4ea00421
...
...
@@ -7,7 +7,7 @@
namespace
Views\comment\Plugin\views\field
;
use
Drupal\views\Plugin\views\field\
Entity
;
use
Drupal\views\Plugin\views\field\
FieldPluginBase
;
use
Drupal\Core\Annotation\Plugin
;
/**
...
...
@@ -20,11 +20,7 @@
* module = "comment"
* )
*/
class
Link
extends
Entity
{
function
construct
()
{
parent
::
construct
();
}
class
Link
extends
FieldPluginBase
{
function
option_definition
()
{
$options
=
parent
::
option_definition
();
...
...
@@ -47,19 +43,16 @@ function options_form(&$form, &$form_state) {
parent
::
options_form
(
$form
,
$form_state
);
}
function
query
()
{
$this
->
ensure_my_table
();
$this
->
add_additional_fields
();
}
function
query
()
{}
function
render
(
$values
)
{
$
value
=
$this
->
get_
value
(
$values
,
'cid'
);
return
$this
->
render_link
(
$
this
->
sanitize_value
(
$value
)
,
$values
);
$
comment
=
$this
->
get_
entity
(
$values
);
return
$this
->
render_link
(
$
comment
,
$values
);
}
function
render_link
(
$data
,
$values
)
{
$text
=
!
empty
(
$this
->
options
[
'text'
])
?
$this
->
options
[
'text'
]
:
t
(
'view'
);
$comment
=
$
this
->
get_value
(
$values
)
;
$comment
=
$
data
;
$nid
=
$comment
->
nid
;
$cid
=
$comment
->
id
();
...
...
lib/Views/comment/Plugin/views/field/NodeLink.php
View file @
4ea00421
...
...
@@ -7,7 +7,7 @@
namespace
Views\comment\Plugin\views\field
;
use
Drupal\views\Plugin\views\field\
Entity
;
use
Drupal\views\Plugin\views\field\
FieldPluginBase
;
use
Drupal\Core\Annotation\Plugin
;
/**
...
...
@@ -20,22 +20,7 @@
* module = "comment"
* )
*/
class
NodeLink
extends
Entity
{
function
construct
()
{
parent
::
construct
();
// Add the node fields that comment_link will need..
$this
->
additional_fields
[
'nid'
]
=
array
(
'field'
=>
'nid'
,
);
$this
->
additional_fields
[
'type'
]
=
array
(
'field'
=>
'type'
,
);
$this
->
additional_fields
[
'comment'
]
=
array
(
'field'
=>
'comment'
,
);
}
class
NodeLink
extends
FieldPluginBase
{
function
option_definition
()
{
$options
=
parent
::
option_definition
();
...
...
@@ -54,14 +39,10 @@ function options_form(&$form, &$form_state) {
parent
::
options_form
(
$form
,
$form_state
);
}
function
query
()
{
$this
->
ensure_my_table
();
$this
->
add_additional_fields
();
}
function
query
()
{}
function
render
(
$values
)
{
// Build fake $node.
$node
=
$this
->
get_value
(
$values
);
$node
=
$this
->
get_entity
(
$values
);
// Call comment.module's hook_link: comment_link($type, $node = NULL, $teaser = FALSE)
// Call node by reference so that something is changed here
...
...
lib/Views/field/Plugin/views/field/Field.php
View file @
4ea00421
...
...
@@ -135,58 +135,15 @@ function get_base_table() {
/**
* Called to add the field to a query.
*
* By default, the only columns added to the query are entity_id and
* entity_type. This is because other needed data is fetched by entity_load().
* Other columns are added only if they are used in groupings, or if
* 'add fields to query' is specifically set to TRUE in the field definition.
*
* The 'add fields to query' switch is used by modules which need all data
* present in the query itself (such as "sphinx").
* By default, all needed data is taken from entities loaded by the query
* plugin. Columns are added only if they are used in groupings.
*/
function
query
(
$use_groupby
=
FALSE
)
{
$this
->
get_base_table
();
$params
=
array
();
if
(
$use_groupby
)
{
// When grouping on a "field API" field (whose "real_field" is set to
// entity_id), retrieve the minimum entity_id to have a valid entity_id to
// pass to field_view_field().
$params
=
array
(
'function'
=>
'min'
,
);
$this
->
ensure_my_table
();
}
// Get the entity type according to the base table of the field.
// Then add it to the query as a formula. That way we can avoid joining
// the field table if all we need is entity_id and entity_type.
$entity_type
=
$this
->
definition
[
'entity_tables'
][
$this
->
base_table
];
$entity_info
=
entity_get_info
(
$entity_type
);
if
(
isset
(
$this
->
relationship
))
{
$this
->
base_table_alias
=
$this
->
relationship
;
}
else
{
$this
->
base_table_alias
=
$this
->
base_table
;
}
// We always need the base field (entity_id / revision_id).
if
(
empty
(
$this
->
definition
[
'is revision'
]))
{
$this
->
field_alias
=
$this
->
query
->
add_field
(
$this
->
base_table_alias
,
$entity_info
[
'entity keys'
][
'id'
],
''
,
$params
);
}
else
{
$this
->
field_alias
=
$this
->
query
->
add_field
(
$this
->
base_table_alias
,
$entity_info
[
'entity keys'
][
'revision'
],
''
,
$params
);
$this
->
aliases
[
'entity_id'
]
=
$this
->
query
->
add_field
(
$this
->
base_table_alias
,
$entity_info
[
'entity keys'
][
'id'
],
''
,
$params
);
}
// The alias needs to be unique, so we use both the field table and the entity type.
$entity_type_alias
=
$this
->
definition
[
'table'
]
.
'_'
.
$entity_type
.
'_entity_type'
;
$this
->
aliases
[
'entity_type'
]
=
$this
->
query
->
add_field
(
NULL
,
"'
$entity_type
'"
,
$entity_type_alias
);
$fields
=
$this
->
additional_fields
;
//
We've already added
entity
_
type
, so we can remove it from the list
.
//
No need to add the
entity
type.
$entity_type_key
=
array_search
(
'entity_type'
,
$fields
);
if
(
$entity_type_key
!==
FALSE
)
{
unset
(
$fields
[
$entity_type_key
]);
...
...
@@ -195,14 +152,11 @@ function query($use_groupby = FALSE) {
if
(
$use_groupby
)
{
// Add the fields that we're actually grouping on.
$options
=
array
();
if
(
$this
->
options
[
'group_column'
]
!=
'entity_id'
)
{
$options
=
array
(
$this
->
options
[
'group_column'
]
=>
$this
->
options
[
'group_column'
]);
}
$options
+=
is_array
(
$this
->
options
[
'group_columns'
])
?
$this
->
options
[
'group_columns'
]
:
array
();
$fields
=
array
();
$rkey
=
$this
->
definition
[
'is revision'
]
?
'FIELD_LOAD_REVISION'
:
'FIELD_LOAD_CURRENT'
;
// Go through the list and determine the actual column name from field api.
...
...
@@ -245,23 +199,14 @@ function query($use_groupby = FALSE) {
$this
->
query
->
add_where_expression
(
0
,
"
$column
IN(
$placeholder
) OR
$column
IS NULL"
,
array
(
$placeholder
=>
$langcode_fallback_candidates
));
}
}
// The revision id inhibits grouping.
// So, stop here if we're using grouping, or if aren't adding all columns to
// the query.
if
(
$use_groupby
||
empty
(
$this
->
definition
[
'add fields to query'
]))
{
return
;
}
$this
->
add_additional_fields
(
array
(
'revision_id'
));
}
/**
* Determine if the field table should be added to the query.
*/
function
add_field_table
(
$use_groupby
)
{
// Grouping is enabled
, or we are explicitly required to do this
.
if
(
$use_groupby
||
!
empty
(
$this
->
definition
[
'add fields to query'
])
)
{
// Grouping is enabled.
if
(
$use_groupby
)
{
return
TRUE
;
}
// This a multiple value field, but "group multiple values" is not checked.
...
...
@@ -621,69 +566,6 @@ function groupby_form_submit(&$form, &$form_state) {
$item
[
'group_columns'
]
=
array_filter
(
$form_state
[
'values'
][
'options'
][
'group_columns'
]);
}
/**
* Load the entities for all fields that are about to be displayed.
*/
function
post_execute
(
&
$values
)
{
if
(
!
empty
(
$values
))
{
// Divide the entity ids by entity type, so they can be loaded in bulk.
$entities_by_type
=
array
();
$revisions_by_type
=
array
();
foreach
(
$values
as
$key
=>
$object
)
{
if
(
isset
(
$this
->
aliases
[
'entity_type'
])
&&
isset
(
$object
->
{
$this
->
aliases
[
'entity_type'
]})
&&
isset
(
$object
->
{
$this
->
field_alias
})
&&
!
isset
(
$values
[
$key
]
->
_field_data
[
$this
->
field_alias
]))
{
$entity_type
=
$object
->
{
$this
->
aliases
[
'entity_type'
]};
if
(
empty
(
$this
->
definition
[
'is revision'
]))
{
$entity_id
=
$object
->
{
$this
->
field_alias
};
$entities_by_type
[
$entity_type
][
$key
]
=
$entity_id
;
}
else
{
$revision_id
=
$object
->
{
$this
->
field_alias
};
$entity_id
=
$object
->
{
$this
->
aliases
[
'entity_id'
]};
$entities_by_type
[
$entity_type
][
$key
]
=
array
(
$entity_id
,
$revision_id
);
}
}
}
// Load the entities.
foreach
(
$entities_by_type
as
$entity_type
=>
$entity_ids
)
{
$entity_info
=
entity_get_info
(
$entity_type
);
if
(
empty
(
$this
->
definition
[
'is revision'
]))
{
$entities
=
entity_load_multiple
(
$entity_type
,
$entity_ids
);
$keys
=
$entity_ids
;
}
else
{
// Revisions can't be loaded multiple, so we have to load them