first import
This commit is contained in:
339
sites/all/modules/views_field_view/LICENSE.txt
Normal file
339
sites/all/modules/views_field_view/LICENSE.txt
Normal file
@@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
21
sites/all/modules/views_field_view/README.txt
Normal file
21
sites/all/modules/views_field_view/README.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
This module allows you to embed a View as a field in another View.
|
||||
|
||||
The View in the view-field can accept argument values from other fields of the parent View, using tokens.
|
||||
|
||||
Here's how:
|
||||
|
||||
1. Before you can add a view-field to a "parent" view, you must create a "child" view.
|
||||
2. Add arguments to that child view. The parent view will be passing argument values to
|
||||
the child so that the child knows what to display. No other settings are necessary,
|
||||
but validators and "argument not present" could be set.
|
||||
3. Create a "parent" view, if not already existing.
|
||||
4. Add child view (Global:View field). The field must be toward the bottom of the field list,
|
||||
or at least underneath the fields that are going to be used as arguments.
|
||||
(E.g., "node id" might be used as an match between the parent and child views,
|
||||
so put the "node id" field before your Global:View field in the list.)
|
||||
5. Select which View and Display to use for the child data (will require doing this in 2 steps
|
||||
- the field must be saved before the display selection is available).
|
||||
6. Find which tokens are available by looking at the "Replacement patterns" list right below the Arguments setting.
|
||||
Type the token replacements, in order, separated by a comma, as the arguments for that view field.
|
||||
These values will be passed to the child. Make sure each field you are passing as an argument is completely clean,
|
||||
as in: no label, no formatting, nothing that would pass into the argument other than the desired text or number.
|
276
sites/all/modules/views_field_view/tests/views_field_view.test
Normal file
276
sites/all/modules/views_field_view/tests/views_field_view.test
Normal file
@@ -0,0 +1,276 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains the test for views_field_view
|
||||
*/
|
||||
|
||||
class viewsFieldViewTestCase extends DrupalWebTestCase {
|
||||
public $nodes = array();
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Views field view test',
|
||||
'description' => 'Tests the views field view.',
|
||||
'group' => 'Views field view'
|
||||
);
|
||||
}
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp('views', 'node', 'views_field_view');
|
||||
|
||||
$this->nodes = array();
|
||||
for ($i = 0; $i <= 10; $i++) {
|
||||
$this->nodes[] = $this->drupalCreateNode();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert method which checks whether the first string is part of the second string.
|
||||
* @param $first
|
||||
* The first value to check.
|
||||
* @param $second
|
||||
* The second value to check.
|
||||
* @param string $message
|
||||
* The message to display along with the assertion.
|
||||
* @param string $group
|
||||
* The type of assertion - examples are "Browser", "PHP".
|
||||
* @return bool TRUE if the assertion succeeded, FALSE otherwise.
|
||||
*/
|
||||
protected function assertContains($first, $second, $message = '', $group = 'Other') {
|
||||
return $this->assert(strpos($second, $first) !== FALSE, $message ? $message : t('Value @first is equal to value @second.', array('@first' => var_export($first, TRUE), '@second' => var_export($second, TRUE))), $group);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @todo
|
||||
* Test normal view embedding.
|
||||
*/
|
||||
function testNormalView() {
|
||||
// Get the child view and add it to the database, so it can be used later.
|
||||
$child_view = $this->view_child_normal();
|
||||
$child_view->save();
|
||||
views_invalidate_cache();
|
||||
|
||||
$parent_view = $this->view_parent_normal();
|
||||
$parent_view->preview();
|
||||
|
||||
|
||||
// Check that the child view has the same title as the parent one
|
||||
foreach ($parent_view->result as $index => $values) {
|
||||
$title = $parent_view->style_plugin->get_field($index, 'title');
|
||||
$child_view_field = $parent_view->style_plugin->get_field($index, 'view');
|
||||
$this->assertContains($title, $child_view_field);
|
||||
}
|
||||
|
||||
// Sadly it's impossible to check the actual result of the child view, because the object is not saved.
|
||||
}
|
||||
|
||||
/**
|
||||
* Test field handler methods in a unit test like way.
|
||||
*/
|
||||
function testFieldHandlerMethods() {
|
||||
$field_handler = new views_field_view_handler_field_view();
|
||||
$this->assertTrue(is_object($field_handler));
|
||||
|
||||
// Test the split_tokens() method.
|
||||
$result = $field_handler->split_tokens('[!uid],[%nid]');
|
||||
$expected = array('[!uid]', '[%nid]');
|
||||
$this->assertEqual($result, $expected, 'The token string has been split correctly (",").');
|
||||
|
||||
$result = $field_handler->split_tokens('[!uid]/[%nid]');
|
||||
$this->assertEqual($result, $expected, 'The token string has been split correctly ("/").');
|
||||
|
||||
$result = $field_handler->split_tokens('[uid]/[nid]');
|
||||
$expected = array('[uid]', '[nid]');
|
||||
$this->assertEqual($result, $expected, 'The token string has been split correctly ("/").');
|
||||
|
||||
// Test the get_token_argument() method.
|
||||
$result = $field_handler->get_token_argument('[!uid]');
|
||||
$expected = array('type' => '!', 'arg' => 'uid');
|
||||
$this->assertEqual($result, $expected, 'Correct token argument info processed ("!").');
|
||||
|
||||
$result = $field_handler->get_token_argument('[%uid]');
|
||||
$expected = array('type' => '%', 'arg' => 'uid');
|
||||
$this->assertEqual($result, $expected, 'Correct token argument info processed ("%").');
|
||||
|
||||
$result = $field_handler->get_token_argument('[uid]');
|
||||
$expected = array('type' => '', 'arg' => 'uid');
|
||||
$this->assertEqual($result, $expected, 'Correct token argument info processed.');
|
||||
|
||||
// Test the token values from a view.
|
||||
$view = $this->view_child_normal();
|
||||
$view->execute();
|
||||
$results = $view->result;
|
||||
|
||||
// Add a value to args, just for the purpose of the !1 token to get a value
|
||||
// from but not affecting the query.
|
||||
$view->args = array(5);
|
||||
|
||||
// Test all the results.
|
||||
foreach ($results as $values) {
|
||||
$map = array(
|
||||
'[!title]' => $values->node_title,
|
||||
'[title]' => $values->node_title,
|
||||
'!1' => 5,
|
||||
'static' => 'static',
|
||||
);
|
||||
// @todo Test the last_render % output.
|
||||
foreach ($map as $token => $value) {
|
||||
$processed_value = $field_handler->get_token_value($token, $values, $view);
|
||||
$this->assertIdentical($value, $processed_value, format_string('Expected @token token output', array('@token' => $token)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @todo
|
||||
* Test aggregation feature.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Contains a normal child view used for the normal view testcase.
|
||||
*
|
||||
* @see viewsFieldViewTestCase::testNormalView
|
||||
* @return view
|
||||
*/
|
||||
function view_child_normal() {
|
||||
$view = new view;
|
||||
$view->name = 'test_vfv_child_normal';
|
||||
$view->description = '';
|
||||
$view->tag = 'default';
|
||||
$view->base_table = 'node';
|
||||
$view->human_name = 'test_vfv_child_normal';
|
||||
$view->core = 7;
|
||||
$view->api_version = '3.0';
|
||||
$view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */
|
||||
|
||||
/* Display: Master */
|
||||
$handler = $view->new_display('default', 'Master', 'default');
|
||||
$handler->display->display_options['access']['type'] = 'perm';
|
||||
$handler->display->display_options['cache']['type'] = 'none';
|
||||
$handler->display->display_options['query']['type'] = 'views_query';
|
||||
$handler->display->display_options['query']['options']['query_comment'] = FALSE;
|
||||
$handler->display->display_options['exposed_form']['type'] = 'basic';
|
||||
$handler->display->display_options['pager']['type'] = 'full';
|
||||
$handler->display->display_options['style_plugin'] = 'default';
|
||||
$handler->display->display_options['row_plugin'] = 'fields';
|
||||
/* Field: Content: Title */
|
||||
$handler->display->display_options['fields']['title']['id'] = 'title';
|
||||
$handler->display->display_options['fields']['title']['table'] = 'node';
|
||||
$handler->display->display_options['fields']['title']['field'] = 'title';
|
||||
$handler->display->display_options['fields']['title']['label'] = '';
|
||||
$handler->display->display_options['fields']['title']['alter']['alter_text'] = 0;
|
||||
$handler->display->display_options['fields']['title']['alter']['make_link'] = 0;
|
||||
$handler->display->display_options['fields']['title']['alter']['absolute'] = 0;
|
||||
$handler->display->display_options['fields']['title']['alter']['word_boundary'] = 0;
|
||||
$handler->display->display_options['fields']['title']['alter']['ellipsis'] = 0;
|
||||
$handler->display->display_options['fields']['title']['alter']['strip_tags'] = 0;
|
||||
$handler->display->display_options['fields']['title']['alter']['trim'] = 0;
|
||||
$handler->display->display_options['fields']['title']['alter']['html'] = 0;
|
||||
$handler->display->display_options['fields']['title']['hide_empty'] = 0;
|
||||
$handler->display->display_options['fields']['title']['empty_zero'] = 0;
|
||||
$handler->display->display_options['fields']['title']['link_to_node'] = 1;
|
||||
/* Contextual filter: Content: Nid */
|
||||
$handler->display->display_options['arguments']['nid']['id'] = 'nid';
|
||||
$handler->display->display_options['arguments']['nid']['table'] = 'node';
|
||||
$handler->display->display_options['arguments']['nid']['field'] = 'nid';
|
||||
$handler->display->display_options['arguments']['nid']['default_argument_type'] = 'fixed';
|
||||
$handler->display->display_options['arguments']['nid']['default_argument_skip_url'] = 0;
|
||||
$handler->display->display_options['arguments']['nid']['summary']['number_of_records'] = '0';
|
||||
$handler->display->display_options['arguments']['nid']['summary']['format'] = 'default_summary';
|
||||
$handler->display->display_options['arguments']['nid']['summary_options']['items_per_page'] = '25';
|
||||
$handler->display->display_options['arguments']['nid']['break_phrase'] = 1;
|
||||
$handler->display->display_options['arguments']['nid']['not'] = 0;
|
||||
|
||||
return $view;
|
||||
}
|
||||
|
||||
/**
|
||||
* Contains a normal parent view used for the normal view testcase.
|
||||
* @see viewsFieldViewTestCase::testNormalView
|
||||
* @return view
|
||||
*/
|
||||
function view_parent_normal() {
|
||||
$view = new view;
|
||||
$view->name = 'test_vfv_parent_normal';
|
||||
$view->description = '';
|
||||
$view->tag = 'default';
|
||||
$view->base_table = 'node';
|
||||
$view->human_name = 'test_vfv_parent_normal';
|
||||
$view->core = 7;
|
||||
$view->api_version = '3.0';
|
||||
$view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */
|
||||
|
||||
/* Display: Master */
|
||||
$handler = $view->new_display('default', 'Master', 'default');
|
||||
$handler->display->display_options['access']['type'] = 'perm';
|
||||
$handler->display->display_options['cache']['type'] = 'none';
|
||||
$handler->display->display_options['query']['type'] = 'views_query';
|
||||
$handler->display->display_options['query']['options']['query_comment'] = FALSE;
|
||||
$handler->display->display_options['exposed_form']['type'] = 'basic';
|
||||
$handler->display->display_options['pager']['type'] = 'full';
|
||||
$handler->display->display_options['style_plugin'] = 'default';
|
||||
$handler->display->display_options['row_plugin'] = 'fields';
|
||||
/* Field: Content: Title */
|
||||
$handler->display->display_options['fields']['title']['id'] = 'title';
|
||||
$handler->display->display_options['fields']['title']['table'] = 'node';
|
||||
$handler->display->display_options['fields']['title']['field'] = 'title';
|
||||
$handler->display->display_options['fields']['title']['label'] = '';
|
||||
$handler->display->display_options['fields']['title']['alter']['alter_text'] = 0;
|
||||
$handler->display->display_options['fields']['title']['alter']['make_link'] = 0;
|
||||
$handler->display->display_options['fields']['title']['alter']['absolute'] = 0;
|
||||
$handler->display->display_options['fields']['title']['alter']['word_boundary'] = 0;
|
||||
$handler->display->display_options['fields']['title']['alter']['ellipsis'] = 0;
|
||||
$handler->display->display_options['fields']['title']['alter']['strip_tags'] = 0;
|
||||
$handler->display->display_options['fields']['title']['alter']['trim'] = 0;
|
||||
$handler->display->display_options['fields']['title']['alter']['html'] = 0;
|
||||
$handler->display->display_options['fields']['title']['hide_empty'] = 0;
|
||||
$handler->display->display_options['fields']['title']['empty_zero'] = 0;
|
||||
$handler->display->display_options['fields']['title']['link_to_node'] = 1;
|
||||
/* Field: Content: Nid */
|
||||
$handler->display->display_options['fields']['nid']['id'] = 'nid';
|
||||
$handler->display->display_options['fields']['nid']['table'] = 'node';
|
||||
$handler->display->display_options['fields']['nid']['field'] = 'nid';
|
||||
$handler->display->display_options['fields']['nid']['alter']['alter_text'] = 0;
|
||||
$handler->display->display_options['fields']['nid']['alter']['make_link'] = 0;
|
||||
$handler->display->display_options['fields']['nid']['alter']['absolute'] = 0;
|
||||
$handler->display->display_options['fields']['nid']['alter']['external'] = 0;
|
||||
$handler->display->display_options['fields']['nid']['alter']['replace_spaces'] = 0;
|
||||
$handler->display->display_options['fields']['nid']['alter']['trim_whitespace'] = 0;
|
||||
$handler->display->display_options['fields']['nid']['alter']['nl2br'] = 0;
|
||||
$handler->display->display_options['fields']['nid']['alter']['word_boundary'] = 1;
|
||||
$handler->display->display_options['fields']['nid']['alter']['ellipsis'] = 1;
|
||||
$handler->display->display_options['fields']['nid']['alter']['more_link'] = 0;
|
||||
$handler->display->display_options['fields']['nid']['alter']['strip_tags'] = 0;
|
||||
$handler->display->display_options['fields']['nid']['alter']['trim'] = 0;
|
||||
$handler->display->display_options['fields']['nid']['alter']['html'] = 0;
|
||||
$handler->display->display_options['fields']['nid']['element_label_colon'] = 1;
|
||||
$handler->display->display_options['fields']['nid']['element_default_classes'] = 1;
|
||||
$handler->display->display_options['fields']['nid']['hide_empty'] = 0;
|
||||
$handler->display->display_options['fields']['nid']['empty_zero'] = 0;
|
||||
$handler->display->display_options['fields']['nid']['hide_alter_empty'] = 1;
|
||||
$handler->display->display_options['fields']['nid']['link_to_node'] = 0;
|
||||
/* Field: Global: View */
|
||||
$handler->display->display_options['fields']['view']['id'] = 'view';
|
||||
$handler->display->display_options['fields']['view']['table'] = 'views';
|
||||
$handler->display->display_options['fields']['view']['field'] = 'view';
|
||||
$handler->display->display_options['fields']['view']['element_label_colon'] = 1;
|
||||
$handler->display->display_options['fields']['view']['element_default_classes'] = 1;
|
||||
$handler->display->display_options['fields']['view']['hide_empty'] = 0;
|
||||
$handler->display->display_options['fields']['view']['empty_zero'] = 0;
|
||||
$handler->display->display_options['fields']['view']['hide_alter_empty'] = 1;
|
||||
$handler->display->display_options['fields']['view']['view'] = 'test_vfv_child_normal';
|
||||
$handler->display->display_options['fields']['view']['arguments'] = '[nid]';
|
||||
$handler->display->display_options['fields']['view']['query_aggregation'] = 0;
|
||||
/* Filter criterion: Content: Published */
|
||||
$handler->display->display_options['filters']['status']['id'] = 'status';
|
||||
$handler->display->display_options['filters']['status']['table'] = 'node';
|
||||
$handler->display->display_options['filters']['status']['field'] = 'status';
|
||||
$handler->display->display_options['filters']['status']['value'] = 1;
|
||||
$handler->display->display_options['filters']['status']['group'] = 1;
|
||||
$handler->display->display_options['filters']['status']['expose']['operator'] = FALSE;
|
||||
|
||||
return $view;
|
||||
}
|
||||
}
|
19
sites/all/modules/views_field_view/views_field_view.css
Normal file
19
sites/all/modules/views_field_view/views_field_view.css
Normal file
@@ -0,0 +1,19 @@
|
||||
#edit-options-view-edit {
|
||||
margin: 15px 0px;
|
||||
background-color: #F3F4EE;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
#edit-options-view-edit .description {
|
||||
display: inline-block;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
#edit-options-view-edit a {
|
||||
margin: 0px 2px;
|
||||
}
|
||||
|
||||
#edit-options-view-edit a em {
|
||||
font-size: 1.1em;
|
||||
font-weight: bold;
|
||||
}
|
16
sites/all/modules/views_field_view/views_field_view.info
Normal file
16
sites/all/modules/views_field_view/views_field_view.info
Normal file
@@ -0,0 +1,16 @@
|
||||
name = Views Field View
|
||||
description = 'Embeds a view inside a view as field'
|
||||
core = 7.x
|
||||
|
||||
package = Views
|
||||
|
||||
dependencies[] = views
|
||||
|
||||
files[] = views_field_view_handler_field_view.inc
|
||||
files[] = tests/views_field_view.test
|
||||
; Information added by drupal.org packaging script on 2012-09-17
|
||||
version = "7.x-1.0"
|
||||
core = "7.x"
|
||||
project = "views_field_view"
|
||||
datestamp = "1347902395"
|
||||
|
17
sites/all/modules/views_field_view/views_field_view.module
Normal file
17
sites/all/modules/views_field_view/views_field_view.module
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* views_field_view.module
|
||||
*
|
||||
* @author
|
||||
* Daniel Wehner <daniel.wehner@erdfisch.de>
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_views_api().
|
||||
*/
|
||||
function views_field_view_views_api() {
|
||||
return array(
|
||||
'api' => '3',
|
||||
);
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Views integration for the views_field_view module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_views_data_alter().
|
||||
*/
|
||||
function views_field_view_views_data_alter(&$data) {
|
||||
$data['views']['view']['field'] = array(
|
||||
'title' => t('View'),
|
||||
'help' => t('Embed a view as a field. This can cause slow performance, so enable some caching.'),
|
||||
'handler' => 'views_field_view_handler_field_view',
|
||||
);
|
||||
$data['views']['view_field'] = array(
|
||||
'title' => t('View (Views field view)'),
|
||||
'help' => t('Embed a view in an area. This can cause slow performance, so enable some caching.'),
|
||||
'area' => array(
|
||||
'help' => t('Embed a views_field_view field in an area. This can also accept argument tokens.'),
|
||||
'handler' => 'views_field_view_handler_field_view',
|
||||
),
|
||||
);
|
||||
}
|
@@ -0,0 +1,614 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Views field view field handler class.
|
||||
*
|
||||
*/
|
||||
|
||||
class views_field_view_handler_field_view extends views_handler_field {
|
||||
/**
|
||||
* If query aggregation is used, all of the arguments for the child view.
|
||||
*
|
||||
* This is a multidimensional array containing field_aliases for the argument's
|
||||
* fields and containing a linear array of all of the results to be used as
|
||||
* arguments in various fields.
|
||||
*/
|
||||
public $child_arguments = array();
|
||||
|
||||
/**
|
||||
* If query aggregation is used, this attribute contains an array of the results
|
||||
* of the aggregated child views.
|
||||
*/
|
||||
public $child_view_results = array();
|
||||
|
||||
/**
|
||||
* If query aggregation is enabled, one instance of the child view to be reused.
|
||||
*
|
||||
* Note, it should never contain arguments or results because they will be
|
||||
* injected into it for rendering.
|
||||
*/
|
||||
public $child_view = FALSE;
|
||||
|
||||
/**
|
||||
* Disable this handler from being used as a 'group by'.
|
||||
*/
|
||||
function use_string_group_by() {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
function option_definition() {
|
||||
$options = parent::option_definition();
|
||||
$options['view'] = array('default' => '');
|
||||
$options['display'] = array('default' => 'default');
|
||||
$options['arguments'] = array('default' => '');
|
||||
$options['query_aggregation'] = array('default' => FALSE, 'bool' => TRUE);
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
function options_form(&$form, &$form_state) {
|
||||
parent::options_form($form, $form_state);
|
||||
|
||||
$view_options = views_get_views_as_options(TRUE);
|
||||
|
||||
$form['views_field_view'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t("View settings"),
|
||||
'#collapsible' => TRUE,
|
||||
'#collapsed' => FALSE,
|
||||
);
|
||||
|
||||
$form['view'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('View'),
|
||||
'#description' => t('Select a view to embed.'),
|
||||
'#default_value' => $this->options['view'],
|
||||
'#options' => $view_options,
|
||||
'#ajax' => array(
|
||||
'path' => views_ui_build_form_url($form_state),
|
||||
),
|
||||
'#submit' => array('views_ui_config_item_form_submit_temporary'),
|
||||
'#executes_submit_callback' => TRUE,
|
||||
'#fieldset' => 'views_field_view',
|
||||
);
|
||||
|
||||
// If there is no view set, use the first one for now.
|
||||
if (count($view_options) && empty($this->options['view'])) {
|
||||
$this->options['view'] = reset(array_keys($view_options));
|
||||
}
|
||||
|
||||
if ($this->options['view']) {
|
||||
$view = views_get_view($this->options['view']);
|
||||
|
||||
$display_options = array();
|
||||
foreach ($view->display as $name => $display) {
|
||||
// Allow to embed a different display as the current one.
|
||||
if ($this->options['view'] != $this->view->name || ($this->view->current_display != $name)) {
|
||||
$display_options[$name] = $display->display_title;
|
||||
}
|
||||
}
|
||||
|
||||
$form['display'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Display'),
|
||||
'#description' => t('Select a view display to use.'),
|
||||
'#default_value' => $this->options['display'],
|
||||
'#options' => $display_options,
|
||||
'#ajax' => array(
|
||||
'path' => views_ui_build_form_url($form_state),
|
||||
),
|
||||
'#submit' => array('views_ui_config_item_form_submit_temporary'),
|
||||
'#executes_submit_callback' => TRUE,
|
||||
'#fieldset' => 'views_field_view',
|
||||
);
|
||||
|
||||
// Provide a way to directly access the views edit link of the child view.
|
||||
// Don't show this link if the current view is the selected child view.
|
||||
if ($this->options['view'] && $this->options['display'] && ($this->view->name != $this->options['view'])) {
|
||||
// use t() here, and set HTML on #link options.
|
||||
$link_text = t('Edit "%view (@display)" view', array('%view' => $view_options[$this->options['view']], '@display' => $this->options['display']));
|
||||
$form['view_edit'] = array(
|
||||
'#type' => 'container',
|
||||
'#fieldset' => 'views_field_view',
|
||||
);
|
||||
$form['view_edit']['view_edit_link'] = array(
|
||||
'#theme' => 'link',
|
||||
'#text' => $link_text,
|
||||
'#path' => 'admin/structure/views/view/' . $this->options['view'] . '/edit/' . $this->options['display'],
|
||||
'#options' => array(
|
||||
'attributes' => array(
|
||||
'target' => '_blank',
|
||||
'class' => array('views-field-view-child-view-edit'),
|
||||
),
|
||||
'html' => TRUE,
|
||||
),
|
||||
'#attached' => array(
|
||||
'css' => array(
|
||||
drupal_get_path('module', 'views_field_view') . '/views_field_view.css',
|
||||
),
|
||||
),
|
||||
'#prefix' => '<span>[</span>',
|
||||
'#suffix' => '<span>]</span>',
|
||||
);
|
||||
$form['view_edit']['description'] = array(
|
||||
'#markup' => t('Use this link to open the current child view\'s edit page in a new window.'),
|
||||
'#prefix' => '<div class="description">',
|
||||
'#suffix' => '</div>',
|
||||
);
|
||||
}
|
||||
|
||||
$form['arguments'] = array(
|
||||
'#title' => t('Contextual filters'),
|
||||
'#description' => t('Use a comma (,) or forwardslash (/) separated list of each contextual filter which should be forwared to the view.
|
||||
See below list of available replacement tokens. Static values are also be passed to child views if they do not match a token format.
|
||||
You could pass static ID\'s or taxonomy terms in this way. E.g. 123 or "my taxonomy term".'),
|
||||
'#type' => 'textfield',
|
||||
'#default_value' => $this->options['arguments'],
|
||||
'#fieldset' => 'views_field_view',
|
||||
);
|
||||
$form['available_tokens'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Replacement patterns'),
|
||||
'#collapsible' => TRUE,
|
||||
'#collapsed' => TRUE,
|
||||
'#value' => $this->get_token_info(),
|
||||
'#fieldset' => 'views_field_view',
|
||||
);
|
||||
|
||||
// It doesn't make sense to allow aggregation unless it's a field handler.
|
||||
if (($this->handler_type == 'field')) {
|
||||
$form['query_aggregation'] = array(
|
||||
'#title' => t('Aggregate queries'),
|
||||
'#description' => t('Views Field View usually runs a separate query for each instance of this field on each row and that can mean a lot of queries.
|
||||
This option attempts to aggregate these queries into one query per instance of this field (regardless of how many rows are displayed).
|
||||
<strong>Currently child views must be configured to "Display all results for the specified field" if no contextual filter is present and
|
||||
query aggregation is enabled.</strong>. This may only work on simple views, please test thoroughly.'),
|
||||
'#type' => 'checkbox',
|
||||
'#default_value' => $this->options['query_aggregation'],
|
||||
'#fieldset' => 'views_field_view',
|
||||
);
|
||||
}
|
||||
|
||||
// Ensure we're working with a SQL view.
|
||||
$views_data = views_fetch_data($view->base_table);
|
||||
if ($views_data['table']['base']['query class'] == 'views_query') {
|
||||
$form['query_aggregation']['#disabled'] = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
$form['alter']['#access'] = FALSE;
|
||||
}
|
||||
|
||||
function query() {
|
||||
$this->add_additional_fields();
|
||||
}
|
||||
|
||||
/**
|
||||
* Run before any fields are rendered.
|
||||
*
|
||||
* This gives the handlers some time to set up before any handler has
|
||||
* been rendered.
|
||||
*
|
||||
* @param array $values
|
||||
* An array of all objects returned from the query.
|
||||
*/
|
||||
function pre_render(&$values) {
|
||||
// Only act if we are attempting to aggregate all of the field
|
||||
// instances into a single query.
|
||||
if ($this->options['view'] && $this->options['query_aggregation']) {
|
||||
// Note: Unlike render, pre_render will be run exactly once per
|
||||
// views_field_view field (not once for each row).
|
||||
$child_view_name = $this->options['view'];
|
||||
$child_view_display = $this->options['display'];
|
||||
|
||||
// Add each argument token configured for this view_field.
|
||||
foreach ($this->split_tokens($this->options['arguments']) as $token) {
|
||||
// Remove the brackets around the token etc..
|
||||
$token_info = $this->get_token_argument($token);
|
||||
$argument = $token_info['arg'];
|
||||
$token_type = $token_info['type'];
|
||||
// Collect all of the values that we intend to use as arguments of our single query.
|
||||
// TODO: Get this to be handled by get_token_value() method too.
|
||||
if (isset($this->view->field[$argument])) {
|
||||
if (isset($this->view->field[$argument]->field_info)) {
|
||||
$field_alias = 'field_' . $this->view->field[$argument]->field;
|
||||
$field_key = key($this->view->field[$argument]->field_info['columns']);
|
||||
}
|
||||
elseif (isset($this->view->field[$argument]->field_alias)) {
|
||||
$field_alias = $this->view->field[$argument]->field_alias;
|
||||
$field_key = 'value';
|
||||
}
|
||||
|
||||
foreach ($values as $value) {
|
||||
if (isset($value->$field_alias)) {
|
||||
$this->child_arguments[$field_alias]['argument_name'] = $field_alias;
|
||||
|
||||
if (is_array($value->$field_alias)) {
|
||||
$field_values = array();
|
||||
|
||||
foreach ($value->$field_alias as $field_item) {
|
||||
switch ($token_type) {
|
||||
case '%':
|
||||
$field_values[] = $field_item['rendered']['#markup'];
|
||||
break;
|
||||
case '!':
|
||||
default:
|
||||
$field_values[] = $field_item['raw'][$field_key];
|
||||
}
|
||||
}
|
||||
$field_value = (count($field_values) > 1) ? $field_values : reset($field_values);
|
||||
$this->child_arguments[$field_alias]['values'][] = $field_value;
|
||||
}
|
||||
else {
|
||||
$this->child_arguments[$field_alias]['values'][] = $value->$field_alias;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we don't have child arguments we should not try to do any of our magic.
|
||||
if (count($this->child_arguments)) {
|
||||
// Cache the child_view in this object to minize our calls to views_get_view.
|
||||
$this->child_view = views_get_view($child_view_name);
|
||||
$child_view = $this->child_view;
|
||||
// Set the appropriate display.
|
||||
$child_view->access($child_view_display);
|
||||
|
||||
// Find the arguments on the child view that we're going to need if the
|
||||
// arguments have been overridden.
|
||||
foreach ($child_view->display['default']->display_options['arguments'] as $argument_name => $argument_value) {
|
||||
if (isset($child_view->display[$child_view_display]->display_options['arguments'][$argument_name])) {
|
||||
$configured_arguments[$argument_name] = $child_view->display[$child_view_display]->display_options['arguments'][$argument_name];
|
||||
}
|
||||
else {
|
||||
$configured_arguments[$argument_name] = $child_view->display['default']->display_options['arguments'][$argument_name];
|
||||
}
|
||||
}
|
||||
|
||||
$argument_ids = array();
|
||||
|
||||
foreach ($this->child_arguments as $child_argument_name => $child_argument) {
|
||||
// Work with the arguments on the child view in the order they are
|
||||
// specified in our views_field_view field settings.
|
||||
$configured_argument = array_shift($configured_arguments);
|
||||
// To be able to later split up our results among the appropriate rows,
|
||||
// we need to add whatever argument fields we're using to the query.
|
||||
$argument_ids[$child_argument_name] = $child_view->add_item($child_view_display, 'field', $configured_argument['table'], $configured_argument['field'], array('exclude' => TRUE));
|
||||
|
||||
if (isset($child_view->pager['items_per_page'])) {
|
||||
$child_view->pager['items_per_page'] = 0;
|
||||
}
|
||||
|
||||
$child_view->build();
|
||||
// Add the WHERE IN clause to this query.
|
||||
$child_view->query->add_where(0, $configured_argument['table'] . '.' . $configured_argument['field'], $child_argument['values']);
|
||||
}
|
||||
|
||||
// Initialize the query object so that we have it to alter.
|
||||
// The child view may have been limited but our result set here should not be.
|
||||
$child_view->build_info['query'] = $child_view->query->query();
|
||||
$child_view->build_info['count_query'] = $child_view->query->query(TRUE);
|
||||
$child_view->build_info['query_args'] = $child_view->query->get_where_args();
|
||||
// Execute the query to retrieve the results.
|
||||
$child_view->execute();
|
||||
|
||||
// Now that the query has run, we need to get the field alias for each argument field
|
||||
// so that it can be identified later.
|
||||
foreach ($argument_ids as $child_argument_name => $argument_id) {
|
||||
$child_alias = (isset($child_view->field[$argument_id]->field_alias) && $child_view->field[$argument_id]->field_alias !== 'unknown') ? $child_view->field[$argument_id]->field_alias : $child_view->field[$argument_id]->real_field;
|
||||
$this->child_arguments[$child_argument_name]['child_view_field_alias'] = $child_alias;
|
||||
}
|
||||
$results = $child_view->result;
|
||||
|
||||
// Finally: Cache the results so that they're easily accessible for the render function.
|
||||
// Loop through the results from the main view so that we can cache the results
|
||||
// relevant to each row.
|
||||
foreach ($values as $value) {
|
||||
// Add an element to the child_view_results array for each of the rows keyed by this view's base_field.
|
||||
$this->child_view_results[$value->{$this->view->base_field}] = array();
|
||||
$child_view_result_row =& $this->child_view_results[$value->{$this->view->base_field}];
|
||||
// Loop through the actual result set looking for matches to these arguments.
|
||||
foreach ($results as $result) {
|
||||
// Assume that we have a matching item until we know that we don't.
|
||||
$matching_item = TRUE;
|
||||
// Check each argument that we care about to ensure that it matches.
|
||||
foreach ($this->child_arguments as $child_argument_field_alias => $child_argument) {
|
||||
// If one of our arguments does not match the argument of this field,
|
||||
// do not add it to this row.
|
||||
if (isset($value->$child_argument_field_alias) && $value->$child_argument_field_alias != $result->{$child_argument['child_view_field_alias']}) {
|
||||
$matching_item = FALSE;
|
||||
}
|
||||
}
|
||||
if ($matching_item) {
|
||||
$child_view_result_row[] = $result;
|
||||
}
|
||||
}
|
||||
|
||||
// Make a best effort attempt at paging.
|
||||
if (isset($this->child_view->pager['items_per_page'])) {
|
||||
$item_limit = $this->child_view->pager['items_per_page'];
|
||||
// If the item limit exists but is set to zero, do not split up the results.
|
||||
if ($item_limit != 0) {
|
||||
$results = array_chunk($results, $item_limit);
|
||||
$offset = (isset($this->child_view->pager['offset']) ? $this->child_view->pager['offset'] : 0);
|
||||
$results = $results[$offset];
|
||||
}
|
||||
}
|
||||
unset($child_view_result_row);
|
||||
}
|
||||
|
||||
// We have essentially built and executed the child view member of this view.
|
||||
// Set it accordingly so that it is not rebuilt during the rendering of each row below.
|
||||
$this->child_view->built = TRUE;
|
||||
$this->child_view->executed = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function render($values) {
|
||||
$output = NULL;
|
||||
// If it's not a field handler and there are no values
|
||||
// Get the first result row from the view and use that.
|
||||
if (($this->handler_type !== 'field') && empty($values) && isset($this->view->result)) {
|
||||
$values = reset($this->view->result);
|
||||
}
|
||||
|
||||
static $running = array();
|
||||
// Protect against the evil / recursion.
|
||||
// Set the variable for yourself, this is not for the normal "user".
|
||||
if (empty($running[$this->options['view']][$this->options['display']]) || variable_get('views_field_view_evil', FALSE)) {
|
||||
if ($this->options['view'] && !$this->options['query_aggregation']) {
|
||||
$running[$this->options['view']][$this->options['display']] = TRUE;
|
||||
$args = array();
|
||||
|
||||
// Only perform this loop if there are actually arguments present.
|
||||
if (!empty($this->options['arguments'])) {
|
||||
// Create array of tokens.
|
||||
foreach ($this->split_tokens($this->options['arguments']) as $token) {
|
||||
$args[] = $this->get_token_value($token, $values, $this->view);
|
||||
}
|
||||
}
|
||||
|
||||
// get view etc… and execute.
|
||||
$view = views_get_view($this->options['view']);
|
||||
|
||||
// Only execute and render the view if the user has access.
|
||||
if ($view->access($this->options['display'])) {
|
||||
$view->set_display($this->options['display']);
|
||||
|
||||
if ($view->display_handler->use_pager()) {
|
||||
// Check whether the pager IDs should be rewritten.
|
||||
$view->init_query();
|
||||
// Find a proper start value for the ascening pager IDs.
|
||||
$start = 0;
|
||||
$pager = $view->display_handler->get_option('pager');
|
||||
if (isset($this->query->pager->options)) {
|
||||
$start = (int) $this->query->pager->options['id'];
|
||||
}
|
||||
|
||||
// Set the pager ID before initializing the pager, so
|
||||
// views_plugin_pager::set_current_page works as expected, which is
|
||||
// called from view::init_pager()
|
||||
$pager['options']['id'] = $start + 1 + $this->view->row_index;
|
||||
$view->display_handler->set_option('pager', $pager);
|
||||
$view->init_pager();
|
||||
}
|
||||
|
||||
$view->pre_execute($args);
|
||||
$view->execute();
|
||||
|
||||
// If there are no results and hide_empty is set.
|
||||
if (empty($view->result) && $this->options['hide_empty']) {
|
||||
$output = '';
|
||||
}
|
||||
// Else just call render on the view object.
|
||||
else {
|
||||
$output = $view->render();
|
||||
}
|
||||
}
|
||||
|
||||
$running[$this->options['view']][$this->options['display']] = FALSE;
|
||||
}
|
||||
// Verify we have a child view (if there were no arguments specified we
|
||||
// won't have one), and that query aggregation was enabled.
|
||||
elseif ($this->child_view && $this->options['view'] && $this->options['query_aggregation']) {
|
||||
$running[$this->options['view']][$this->options['display']] = TRUE;
|
||||
$child_view = $this->child_view;
|
||||
// Only execute and render the view if the user has access.
|
||||
if ($child_view->access($this->options['display'])) {
|
||||
$results = $this->child_view_results[$values->{$this->view->base_field}];
|
||||
// If there are no results and hide_empty is set.
|
||||
if (empty($results) && $this->options['hide_empty']) {
|
||||
$output = '';
|
||||
}
|
||||
else {
|
||||
// Inject the appropriate result set before rendering the view.
|
||||
$child_view->result = $results;
|
||||
|
||||
if (isset($child_view->style_plugin->rendered_fields)) {
|
||||
unset($child_view->style_plugin->rendered_fields);
|
||||
}
|
||||
|
||||
$output = $child_view->render();
|
||||
}
|
||||
|
||||
$running[$this->options['view']][$this->options['display']] = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
$output = t('Recursion, stop!');
|
||||
}
|
||||
|
||||
if (!empty($output)) {
|
||||
// Add the rendered output back to the $values object
|
||||
// so it is available in $view->result objects.
|
||||
$values->{'views_field_view_' . $this->options['id']} = $output;
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get field values from tokens.
|
||||
*
|
||||
* @param string $token
|
||||
* token string. E.g. explode(',', $this->options['args']);
|
||||
* @param View $view
|
||||
* Full view object to get token values from.
|
||||
*
|
||||
* @return array
|
||||
* An array of raw argument values, returned in the same order as the token
|
||||
* were passed in.
|
||||
*/
|
||||
function get_token_value($token, $values, $view) {
|
||||
$token_info = $this->get_token_argument($token);
|
||||
$arg = $token_info['arg'];
|
||||
$token_type = $token_info['type'];
|
||||
|
||||
// Collect all of the values that we intend to use as arguments of our single query.
|
||||
if (isset($view->field[$arg])) {
|
||||
switch ($token_type) {
|
||||
case '%':
|
||||
$value = $view->field[$arg]->last_render;
|
||||
break;
|
||||
case '!':
|
||||
default:
|
||||
$value = $view->field[$arg]->get_value($values);
|
||||
break;
|
||||
}
|
||||
}
|
||||
elseif (isset($view->args[$arg - 1])) {
|
||||
switch ($token_type) {
|
||||
case '%':
|
||||
// Get an array of argument keys. So we can use the index as an
|
||||
// identifier.
|
||||
$keys = array_keys($view->argument);
|
||||
$value = $view->argument[$keys[$arg - 1]]->get_title();
|
||||
break;
|
||||
case '!':
|
||||
default:
|
||||
$value = $view->args[$arg - 1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$value = check_plain(trim($token, '\'"'));
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the argument type and raw argument from a token.
|
||||
* E.g. [!test_token] will return "array('type' => '!', 'arg' => test_token)".
|
||||
*
|
||||
* @param string $token
|
||||
* A single token string.
|
||||
*
|
||||
* @return array
|
||||
* An array containing type and arg (As described above).
|
||||
*/
|
||||
function get_token_argument($token) {
|
||||
// Trim whitespace and remove the brackets around the token.
|
||||
$argument = trim(trim($token), '[]');
|
||||
$diff = ltrim($argument, '!..%');
|
||||
$token_type = '';
|
||||
|
||||
if ($argument != $diff) {
|
||||
$token_type = $argument[0];
|
||||
// Make the new argument the diff (without token type character).
|
||||
$argument = $diff;
|
||||
}
|
||||
|
||||
return array(
|
||||
'type' => $token_type,
|
||||
'arg' => $argument,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns array of tokens/values to be used in child views.
|
||||
* String containing tokens is split on either "," or "/" characters.
|
||||
*
|
||||
* @param string $token_string
|
||||
* The string of tokens to split.
|
||||
*
|
||||
* @return array
|
||||
* An array of split token strings.
|
||||
*/
|
||||
function split_tokens($token_string) {
|
||||
return preg_split('/,|\//', $token_string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get available field tokens, code/logic stolen from views_handler_field.inc.
|
||||
*
|
||||
* @return string
|
||||
* A full HTML string, containing a list of available tokens.
|
||||
*/
|
||||
public function get_token_info() {
|
||||
// Get a list of the available fields and arguments for token replacement.
|
||||
$options = array();
|
||||
|
||||
foreach ($this->view->display_handler->get_handlers('field') as $field => $handler) {
|
||||
$options[t('Fields')]["[!$field]"] = $handler->ui_name() . ' (' . t('raw') . ')';
|
||||
$options[t('Fields')]["[%$field]"] = $handler->ui_name() . ' (' . t('rendered') . ')';
|
||||
// We only use fields up to (and including) this one.
|
||||
if ($field == $this->options['id']) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// This lets us prepare the key as we want it printed.
|
||||
$count = 0;
|
||||
|
||||
foreach ($this->view->display_handler->get_handlers('argument') as $arg => $handler) {
|
||||
$options[t('Arguments')]['%' . ++$count] = t('@argument title', array('@argument' => $handler->ui_name()));
|
||||
$options[t('Arguments')]['!' . $count] = t('@argument input', array('@argument' => $handler->ui_name()));
|
||||
}
|
||||
|
||||
// Add replacements for query string parameters.
|
||||
foreach ($_GET as $param => $val) {
|
||||
if (is_array($val)) {
|
||||
$val = implode(', ', $val);
|
||||
}
|
||||
$options[t('Query string')]["[%$param]"] = strip_tags(decode_entities($val));
|
||||
}
|
||||
|
||||
$this->document_self_tokens($options[t('Fields')]);
|
||||
|
||||
// Default text.
|
||||
$output = '<p>' . t('You must add some additional fields to this display before using this field.
|
||||
These fields may be marked as <em>Exclude from display</em> if you prefer. Note that due to rendering order,
|
||||
you cannot use fields that come after this field; if you need a field not listed here, rearrange your fields.') . '</p>';
|
||||
|
||||
// We have some options, so make a list.
|
||||
if (!empty($options)) {
|
||||
$output = '<p>' . t('The following tokens are available for this field. Note that due to rendering order,
|
||||
you cannot use fields that come after this field; if you need a field that is not listed here, re-arrange your fields.') . '</p>';
|
||||
|
||||
foreach (array_keys($options) as $type) {
|
||||
if (!empty($options[$type])) {
|
||||
$items = array();
|
||||
foreach ($options[$type] as $key => $value) {
|
||||
$items[] = $key . ' == ' . $value;
|
||||
}
|
||||
$output .= theme('item_list',
|
||||
array(
|
||||
'items' => $items,
|
||||
'type' => $type
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$output .= '<p><em>' . t('Using rendered (%) tokens can cause unexpected behaviour, as this will use the last output of the field.
|
||||
This could be re written output also. If no prefix is used in the token pattern, "!" will be used as a default.') . '</em></p>';
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
} // views_field_view_handler_field_view.
|
Reference in New Issue
Block a user