merged entityreference submodule
This commit is contained in:
		@@ -0,0 +1,93 @@
 | 
			
		||||
diff --git a/plugins/selection/EntityReference_SelectionHandler_Generic.class.php b/plugins/selection/EntityReference_SelectionHandler_Generic.class.php
 | 
			
		||||
index 7db4045..f3ff067 100644
 | 
			
		||||
--- a/plugins/selection/EntityReference_SelectionHandler_Generic.class.php
 | 
			
		||||
+++ b/plugins/selection/EntityReference_SelectionHandler_Generic.class.php
 | 
			
		||||
@@ -307,6 +307,27 @@ class EntityReference_SelectionHandler_Generic_node extends EntityReference_Sele
 | 
			
		||||
  * This only exists to workaround core bugs.
 | 
			
		||||
  */
 | 
			
		||||
 class EntityReference_SelectionHandler_Generic_user extends EntityReference_SelectionHandler_Generic {
 | 
			
		||||
+  /**
 | 
			
		||||
+   * Implements EntityReferenceHandler::settingsForm().
 | 
			
		||||
+   */
 | 
			
		||||
+  public static function settingsForm($field, $instance) {
 | 
			
		||||
+    $settings = $field['settings']['handler_settings'];
 | 
			
		||||
+    $form = parent::settingsForm($field, $instance);
 | 
			
		||||
+    $form['referenceable_roles'] = array(
 | 
			
		||||
+      '#type' => 'checkboxes',
 | 
			
		||||
+      '#title' => t('User roles that can be referenced'),
 | 
			
		||||
+      '#default_value' => isset($settings['referenceable_roles']) ? array_filter($settings['referenceable_roles']) : array(),
 | 
			
		||||
+      '#options' => user_roles(TRUE),
 | 
			
		||||
+    );
 | 
			
		||||
+    $form['referenceable_status'] = array(
 | 
			
		||||
+      '#type' => 'checkboxes',
 | 
			
		||||
+      '#title' => t('User status that can be referenced'),
 | 
			
		||||
+      '#default_value' => isset($settings['referenceable_status']) ? array_filter($settings['referenceable_status']) : array('active' => 'active'),
 | 
			
		||||
+      '#options' => array('active' => t('Active'), 'blocked' => t('Blocked')),
 | 
			
		||||
+    );
 | 
			
		||||
+    return $form;
 | 
			
		||||
+  }
 | 
			
		||||
+
 | 
			
		||||
   public function buildEntityFieldQuery($match = NULL, $match_operator = 'CONTAINS') {
 | 
			
		||||
     $query = parent::buildEntityFieldQuery($match, $match_operator);
 | 
			
		||||
 
 | 
			
		||||
@@ -315,21 +336,33 @@ class EntityReference_SelectionHandler_Generic_user extends EntityReference_Sele
 | 
			
		||||
       $query->propertyCondition('name', $match, $match_operator);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
-    // Adding the 'user_access' tag is sadly insufficient for users: core
 | 
			
		||||
-    // requires us to also know about the concept of 'blocked' and
 | 
			
		||||
-    // 'active'.
 | 
			
		||||
-    if (!user_access('administer users')) {
 | 
			
		||||
-      $query->propertyCondition('status', 1);
 | 
			
		||||
+    $field = $this->field;
 | 
			
		||||
+    $settings = $field['settings']['handler_settings'];
 | 
			
		||||
+    $referenceable_roles = isset($settings['referenceable_roles']) ? array_filter($settings['referenceable_roles']) : array();
 | 
			
		||||
+    $referenceable_status = isset($settings['referenceable_status']) ? array_filter($settings['referenceable_status']) : array('active' => 'active');
 | 
			
		||||
+
 | 
			
		||||
+    // If this filter is not filled, use the users access permissions.
 | 
			
		||||
+    if (empty($referenceable_status)) {
 | 
			
		||||
+      // Adding the 'user_access' tag is sadly insufficient for users: core
 | 
			
		||||
+      // requires us to also know about the concept of 'blocked' and 'active'.
 | 
			
		||||
+      if (!user_access('administer users')) {
 | 
			
		||||
+        $query->propertyCondition('status', 1);
 | 
			
		||||
+      }
 | 
			
		||||
+    }
 | 
			
		||||
+    elseif (count($referenceable_status) == 1) {
 | 
			
		||||
+      $values = array('active' => 1, 'blocked' => 0);
 | 
			
		||||
+      $query->propertyCondition('status', $values[key($referenceable_status)]);
 | 
			
		||||
     }
 | 
			
		||||
+
 | 
			
		||||
     return $query;
 | 
			
		||||
   }
 | 
			
		||||
 
 | 
			
		||||
   public function entityFieldQueryAlter(SelectQueryInterface $query) {
 | 
			
		||||
+    $conditions = &$query->conditions();
 | 
			
		||||
     if (user_access('administer users')) {
 | 
			
		||||
-      // In addition, if the user is administrator, we need to make sure to
 | 
			
		||||
+      // If the user is administrator, we need to make sure to
 | 
			
		||||
       // match the anonymous user, that doesn't actually have a name in the
 | 
			
		||||
       // database.
 | 
			
		||||
-      $conditions = &$query->conditions();
 | 
			
		||||
       foreach ($conditions as $key => $condition) {
 | 
			
		||||
         if ($condition['field'] == 'users.name') {
 | 
			
		||||
           // Remove the condition.
 | 
			
		||||
@@ -356,6 +389,19 @@ class EntityReference_SelectionHandler_Generic_user extends EntityReference_Sele
 | 
			
		||||
         }
 | 
			
		||||
       }
 | 
			
		||||
     }
 | 
			
		||||
+
 | 
			
		||||
+    $field = $this->field;
 | 
			
		||||
+    $settings = $field['settings']['handler_settings'];
 | 
			
		||||
+    $referenceable_roles = isset($settings['referenceable_roles']) ? array_filter($settings['referenceable_roles']) : array();
 | 
			
		||||
+    if (!$referenceable_roles || !empty($referenceable_roles[DRUPAL_AUTHENTICATED_RID])) {
 | 
			
		||||
+      // Return early if "authenticated user" choosen.
 | 
			
		||||
+      return;
 | 
			
		||||
+    }
 | 
			
		||||
+
 | 
			
		||||
+    if (!isset($referenceable_roles[DRUPAL_AUTHENTICATED_RID])) {
 | 
			
		||||
+      $query->join('users_roles', 'users_roles', 'users.uid = users_roles.uid');
 | 
			
		||||
+      $query->condition('users_roles.rid', array_keys($referenceable_roles), 'IN');
 | 
			
		||||
+    }
 | 
			
		||||
   }
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										339
									
								
								sites/all/modules/contrib/fields/entityreference/LICENSE.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										339
									
								
								sites/all/modules/contrib/fields/entityreference/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.
 | 
			
		||||
							
								
								
									
										16
									
								
								sites/all/modules/contrib/fields/entityreference/README.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								sites/all/modules/contrib/fields/entityreference/README.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
			
		||||
DESCRIPTION
 | 
			
		||||
===========
 | 
			
		||||
Provides a field type that can reference arbitrary entities.
 | 
			
		||||
 | 
			
		||||
SITE BUILDERS
 | 
			
		||||
=============
 | 
			
		||||
Note that when using a select widget, Entity reference loads all the
 | 
			
		||||
entities in that list in order to get the entity's label. If there are
 | 
			
		||||
too many loaded entities that site might reach its memory limit and crash
 | 
			
		||||
(also known as WSOD). In such a case you are advised to change the widget
 | 
			
		||||
to "autocomplete". If you get a WSOD when trying to edit the field
 | 
			
		||||
settings, you can reach the widget settings directly by navigation to
 | 
			
		||||
 | 
			
		||||
  admin/structure/types/manage/[ENTITY-TYPE]/fields/[FIELD-NAME]/widget-type
 | 
			
		||||
 | 
			
		||||
Replace ENTITY-TYPE and FIELD_NAME with the correct values.
 | 
			
		||||
@@ -0,0 +1,4 @@
 | 
			
		||||
 | 
			
		||||
.entityreference-settings {
 | 
			
		||||
  margin-left: 1.5em;
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,26 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @file
 | 
			
		||||
 * Support for processing entity reference fields in devel generate.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
function entityreference_devel_generate($object, $field, $instance, $bundle) {
 | 
			
		||||
  if (field_behaviors_widget('multiple values', $instance) == FIELD_BEHAVIOR_CUSTOM) {
 | 
			
		||||
    return devel_generate_multiple('_entityreference_devel_generate', $object, $field, $instance, $bundle);
 | 
			
		||||
  }
 | 
			
		||||
  else {
 | 
			
		||||
    return _entityreference_devel_generate($object, $field, $instance, $bundle);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _entityreference_devel_generate($object, $field, $instance, $bundle) {
 | 
			
		||||
  $object_field = array();
 | 
			
		||||
  // Get all the entity that are referencable here.
 | 
			
		||||
  $referencable_entity = entityreference_get_selection_handler($field, $instance)->getReferencableEntities();
 | 
			
		||||
  if (is_array($referencable_entity) && !empty($referencable_entity)) {
 | 
			
		||||
    // Get a random key.
 | 
			
		||||
    $object_field['target_id'] = array_rand($referencable_entity);
 | 
			
		||||
  }
 | 
			
		||||
  return $object_field;
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,90 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @file
 | 
			
		||||
 * Provide Diff module field callbacks for the Entity Reference module.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Diff field callback for preloading entities.
 | 
			
		||||
 */
 | 
			
		||||
function entityreference_field_diff_view_prepare(&$old_items, &$new_items, $context) {
 | 
			
		||||
  $field = $context['field'];
 | 
			
		||||
 | 
			
		||||
  // Build an array of entities ID.
 | 
			
		||||
  $entity_ids = array();
 | 
			
		||||
  foreach (array_merge_recursive($old_items, $new_items) as $item) {
 | 
			
		||||
    $entity_ids[] = $item['target_id'];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Load those entities and loop through them to extract their labels.
 | 
			
		||||
  $entities = entity_load($field['settings']['target_type'], $entity_ids);
 | 
			
		||||
 | 
			
		||||
  foreach ($old_items as $delta => $info) {
 | 
			
		||||
    $old_items[$delta]['entity'] = isset($entities[$info['target_id']]) ? $entities[$info['target_id']] : NULL;
 | 
			
		||||
  }
 | 
			
		||||
  foreach ($new_items as $delta => $info) {
 | 
			
		||||
    $new_items[$delta]['entity'] = isset($entities[$info['target_id']]) ? $entities[$info['target_id']] : NULL;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Diff field callback for parsing entity field comparative values.
 | 
			
		||||
 */
 | 
			
		||||
function entityreference_field_diff_view($items, $context) {
 | 
			
		||||
  $field = $context['field'];
 | 
			
		||||
  $instance = $context['instance'];
 | 
			
		||||
  $settings = $context['settings'];
 | 
			
		||||
  $entity_type = $field['settings']['target_type'];
 | 
			
		||||
 | 
			
		||||
  $diff_items = array();
 | 
			
		||||
 | 
			
		||||
  // We populate as much as possible to allow the best flexability in any
 | 
			
		||||
  // string overrides.
 | 
			
		||||
  $t_args = array();
 | 
			
		||||
  $t_args['!entity_type'] = $entity_type;
 | 
			
		||||
 | 
			
		||||
  $entity_info = entity_get_info($entity_type);
 | 
			
		||||
  $t_args['!entity_type_label'] = $entity_info['label'];
 | 
			
		||||
 | 
			
		||||
  foreach ($items as $delta => $item) {
 | 
			
		||||
    if (isset($item['entity'])) {
 | 
			
		||||
      $output = array();
 | 
			
		||||
 | 
			
		||||
      list($id,, $bundle) = entity_extract_ids($entity_type, $item['entity']);
 | 
			
		||||
      $t_args['!id'] = $id;
 | 
			
		||||
      $t_args['!bundle'] = $bundle;
 | 
			
		||||
      $t_args['!diff_entity_label'] = entity_label($entity_type, $item['entity']);
 | 
			
		||||
 | 
			
		||||
      $output['entity'] = t('!diff_entity_label', $t_args);
 | 
			
		||||
      if ($settings['show_id']) {
 | 
			
		||||
        $output['id'] = t('ID: !id', $t_args);
 | 
			
		||||
      }
 | 
			
		||||
      $diff_items[$delta] = implode('; ', $output);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return $diff_items;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Provide default field comparison options.
 | 
			
		||||
 */
 | 
			
		||||
function entityreference_field_diff_default_options($field_type) {
 | 
			
		||||
  return array(
 | 
			
		||||
    'show_id' => 0,
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Provide a form for setting the field comparison options.
 | 
			
		||||
 */
 | 
			
		||||
function entityreference_field_diff_options_form($field_type, $settings) {
 | 
			
		||||
  $options_form = array();
 | 
			
		||||
  $options_form['show_id'] = array(
 | 
			
		||||
    '#type' => 'checkbox',
 | 
			
		||||
    '#title' => t('Show ID'),
 | 
			
		||||
    '#default_value' => $settings['show_id'],
 | 
			
		||||
  );
 | 
			
		||||
  return $options_form;
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,121 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @file
 | 
			
		||||
 * Feeds mapping implementation for the Entity reference module
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Implements hook_feeds_processor_targets_alter().
 | 
			
		||||
 *
 | 
			
		||||
 * @see FeedsNodeProcessor::getMappingTargets().
 | 
			
		||||
 */
 | 
			
		||||
function entityreference_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_name) {
 | 
			
		||||
 | 
			
		||||
  foreach (field_info_instances($entity_type, $bundle_name) as $name => $instance) {
 | 
			
		||||
    $info = field_info_field($name);
 | 
			
		||||
    if ($info['type'] == 'entityreference') {
 | 
			
		||||
      $targets[$name] = array(
 | 
			
		||||
        'name'        => check_plain($instance['label']),
 | 
			
		||||
        'callback'    => 'entityreference_feeds_set_target',
 | 
			
		||||
        'description' => t('The field instance @label of @id', array(
 | 
			
		||||
          '@label' => $instance['label'],
 | 
			
		||||
          '@id'    => $name,
 | 
			
		||||
        )),
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Entity reference callback for mapping.
 | 
			
		||||
 *
 | 
			
		||||
 * When the callback is invoked, $target contains the name of the field the
 | 
			
		||||
 * user has decided to map to and $value contains the value of the feed item
 | 
			
		||||
 * element the user has picked as a source.
 | 
			
		||||
 *
 | 
			
		||||
 * @param $source
 | 
			
		||||
 *   A FeedsSource object.
 | 
			
		||||
 * @param $entity
 | 
			
		||||
 *   The entity to map to.
 | 
			
		||||
 * @param $target
 | 
			
		||||
 *   The target key on $entity to map to.
 | 
			
		||||
 * @param $value
 | 
			
		||||
 *   The value to map. MUST be an array.
 | 
			
		||||
 * @param $mapping
 | 
			
		||||
 *   Array of mapping settings for current value.
 | 
			
		||||
 * @param $input_format
 | 
			
		||||
 *   TRUE if an input format should be applied.
 | 
			
		||||
 */
 | 
			
		||||
function entityreference_feeds_set_target($source, $entity, $target, $value, $mapping, $input_format = FALSE) {
 | 
			
		||||
 | 
			
		||||
  // Don't do anything if we weren't given any data.
 | 
			
		||||
  if (empty($value)) {
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Assume that the passed in value could really be any number of values.
 | 
			
		||||
  if (is_array($value)) {
 | 
			
		||||
    $values = $value;
 | 
			
		||||
  }
 | 
			
		||||
  else {
 | 
			
		||||
    $values = array($value);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Get some useful field information.
 | 
			
		||||
  $info = field_info_field($target);
 | 
			
		||||
 | 
			
		||||
  // Set the language of the field depending on the mapping.
 | 
			
		||||
  $language = isset($mapping['language']) ? $mapping['language'] : LANGUAGE_NONE;
 | 
			
		||||
 | 
			
		||||
  // Iterate over all values.
 | 
			
		||||
  $iterator = 0;
 | 
			
		||||
  $field = isset($entity->$target) ? $entity->$target : array();
 | 
			
		||||
  foreach ($values as $value) {
 | 
			
		||||
 | 
			
		||||
    // Only process if this value was set for this instance.
 | 
			
		||||
    if ($value) {
 | 
			
		||||
 | 
			
		||||
      // Fetch the entity ID resulting from the mapping table look-up.
 | 
			
		||||
      $entity_id = db_query(
 | 
			
		||||
        'SELECT entity_id FROM {feeds_item} WHERE guid = :guid',
 | 
			
		||||
        array(':guid' => $value)
 | 
			
		||||
      )->fetchField();
 | 
			
		||||
 | 
			
		||||
      /*
 | 
			
		||||
       * Only add a reference to an existing entity ID if there exists a
 | 
			
		||||
       * mapping between it and the provided GUID.  In cases where no such
 | 
			
		||||
       * mapping exists (yet), don't do anything here.  There may be a mapping
 | 
			
		||||
       * defined later in the CSV file.  If so, and the user re-runs the import
 | 
			
		||||
       * (as a second pass), we can add this reference then.  (The "Update
 | 
			
		||||
       * existing nodes" option must be selected during the second pass.)
 | 
			
		||||
       */
 | 
			
		||||
      if ($entity_id) {
 | 
			
		||||
 | 
			
		||||
        // Assign the target ID.
 | 
			
		||||
        $field[$language][$iterator]['target_id']   = $entity_id;
 | 
			
		||||
      }
 | 
			
		||||
      else /* there is no $entity_id, no mapping */ {
 | 
			
		||||
 | 
			
		||||
        /*
 | 
			
		||||
         * Feeds stores a hash of every line imported from CSVs in order to
 | 
			
		||||
         * make the import process more efficient by ignoring lines it's
 | 
			
		||||
         * already seen.  We need to short-circuit this process in this case
 | 
			
		||||
         * because users may want to re-import the same line as an update later
 | 
			
		||||
         * when (and if) a map to a reference exists.  So in order to provide
 | 
			
		||||
         * this opportunity later, we need to destroy the hash.
 | 
			
		||||
         */
 | 
			
		||||
        unset($entity->feeds_item->hash);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Break out of the loop if this field is single-valued.
 | 
			
		||||
    if ($info['cardinality'] == 1) {
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    $iterator++;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Add the field to the entity definition.
 | 
			
		||||
  $entity->{$target} = $field;
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,30 @@
 | 
			
		||||
name = Entity Reference
 | 
			
		||||
description = Provides a field that can reference other entities.
 | 
			
		||||
core = 7.x
 | 
			
		||||
package = Fields
 | 
			
		||||
dependencies[] = entity
 | 
			
		||||
dependencies[] = ctools
 | 
			
		||||
 | 
			
		||||
; Migrate handler.
 | 
			
		||||
files[] = entityreference.migrate.inc
 | 
			
		||||
 | 
			
		||||
; Our plugins interfaces and abstract implementations.
 | 
			
		||||
files[] = plugins/selection/abstract.inc
 | 
			
		||||
files[] = plugins/selection/views.inc
 | 
			
		||||
files[] = plugins/behavior/abstract.inc
 | 
			
		||||
 | 
			
		||||
files[] = views/entityreference_plugin_display.inc
 | 
			
		||||
files[] = views/entityreference_plugin_style.inc
 | 
			
		||||
files[] = views/entityreference_plugin_row_fields.inc
 | 
			
		||||
 | 
			
		||||
; Tests.
 | 
			
		||||
files[] = tests/entityreference.handlers.test
 | 
			
		||||
files[] = tests/entityreference.taxonomy.test
 | 
			
		||||
files[] = tests/entityreference.admin.test
 | 
			
		||||
 | 
			
		||||
; Information added by drupal.org packaging script on 2012-11-18
 | 
			
		||||
version = "7.x-1.0"
 | 
			
		||||
core = "7.x"
 | 
			
		||||
project = "entityreference"
 | 
			
		||||
datestamp = "1353230808"
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,164 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Implements hook_uninstall().
 | 
			
		||||
 */
 | 
			
		||||
function entityreference_uninstall() {
 | 
			
		||||
  variable_del('entityreference:base-tables');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Implements hook_field_schema().
 | 
			
		||||
 */
 | 
			
		||||
function entityreference_field_schema($field) {
 | 
			
		||||
  if ($field['type'] == 'entityreference') {
 | 
			
		||||
    // Load the base table configuration from the cache.
 | 
			
		||||
    $base_tables = variable_get('entityreference:base-tables', array());
 | 
			
		||||
 | 
			
		||||
    $schema = array(
 | 
			
		||||
      'columns' => array(
 | 
			
		||||
        'target_id' => array(
 | 
			
		||||
          'description' => 'The id of the target entity.',
 | 
			
		||||
          'type' => 'int',
 | 
			
		||||
          'unsigned' => TRUE,
 | 
			
		||||
          'not null' => TRUE,
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
      'indexes' => array(
 | 
			
		||||
        'target_id' => array('target_id'),
 | 
			
		||||
      ),
 | 
			
		||||
      'foreign keys' => array(),
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // Create a foreign key to the target entity type base type, if available.
 | 
			
		||||
    $entity_type = $field['settings']['target_type'];
 | 
			
		||||
    if (isset($base_tables[$entity_type])) {
 | 
			
		||||
      list($base_table, $id_column) = $base_tables[$entity_type];
 | 
			
		||||
      $schema['foreign keys'][$base_table] = array(
 | 
			
		||||
        'table' => $base_table,
 | 
			
		||||
        'columns' => array('target_id' => $id_column),
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Invoke the behaviors to allow them to change the schema.
 | 
			
		||||
    foreach (entityreference_get_behavior_handlers($field) as $handler) {
 | 
			
		||||
      $handler->schema_alter($schema, $field);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return $schema;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Update the field configuration to the new plugin structure.
 | 
			
		||||
 */
 | 
			
		||||
function entityreference_update_7000() {
 | 
			
		||||
  // Enable ctools.
 | 
			
		||||
  if (!module_enable(array('ctools'))) {
 | 
			
		||||
    throw new DrupalUpdateException('This version of Entity Reference requires ctools, but it could not be enabled.');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Get the list of fields of type 'entityreference'.
 | 
			
		||||
  $fields = array();
 | 
			
		||||
  foreach (field_info_fields() as $field_name => $field) {
 | 
			
		||||
    // Update the field configuration.
 | 
			
		||||
    if ($field['type'] == 'entityreference') {
 | 
			
		||||
      $settings = &$field['settings'];
 | 
			
		||||
      if (!isset($settings['handler'])) {
 | 
			
		||||
        $settings['handler'] = 'base';
 | 
			
		||||
        $settings['handler_settings']['target_bundles'] = $settings['target_bundles'];
 | 
			
		||||
        unset($settings['target_bundles']);
 | 
			
		||||
        field_update_field($field);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Update the instance configurations.
 | 
			
		||||
    foreach ($field['bundles'] as $entity_type => $bundles) {
 | 
			
		||||
      foreach ($bundles as $bundle) {
 | 
			
		||||
        $instance = field_info_instance($entity_type, $field_name, $bundle);
 | 
			
		||||
        $save = FALSE;
 | 
			
		||||
        if ($instance['widget']['type'] == 'entityreference_autocomplete') {
 | 
			
		||||
          $instance['widget']['type'] = 'entityreference_autocomplete_tags';
 | 
			
		||||
          $save = TRUE;
 | 
			
		||||
        }
 | 
			
		||||
        // When the autocomplete path is the default value, remove it from
 | 
			
		||||
        // the configuration.
 | 
			
		||||
        if (isset($instance['widget']['settings']['path']) && $instance['widget']['settings']['path'] == 'entityreference/autocomplete') {
 | 
			
		||||
          unset($instance['widget']['settings']['path']);
 | 
			
		||||
          $save = TRUE;
 | 
			
		||||
        }
 | 
			
		||||
        if ($save) {
 | 
			
		||||
          field_update_instance($instance);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Drop "target_type" from the field schema.
 | 
			
		||||
 */
 | 
			
		||||
function entityreference_update_7001() {
 | 
			
		||||
  if (!module_exists('field_sql_storage')) {
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  foreach (field_info_fields() as $field_name => $field) {
 | 
			
		||||
    if ($field['type'] != 'entityreference') {
 | 
			
		||||
      // Not an entity reference field.
 | 
			
		||||
      continue;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Update the field settings.
 | 
			
		||||
    $field = field_info_field($field_name);
 | 
			
		||||
    unset($field['indexes']['target_entity']);
 | 
			
		||||
    $field['indexes']['target_id'] = array('target_id');
 | 
			
		||||
    field_update_field($field);
 | 
			
		||||
 | 
			
		||||
    if ($field['storage']['type'] !== 'field_sql_storage') {
 | 
			
		||||
      // Field doesn't use SQL storage, we cannot modify the schema.
 | 
			
		||||
      continue;
 | 
			
		||||
    }
 | 
			
		||||
    $table_name = _field_sql_storage_tablename($field);
 | 
			
		||||
    $revision_name = _field_sql_storage_revision_tablename($field);
 | 
			
		||||
 | 
			
		||||
    db_drop_index($table_name, $field_name . '_target_entity');
 | 
			
		||||
    db_drop_index($table_name, $field_name . '_target_id');
 | 
			
		||||
    db_drop_field($table_name, $field_name . '_target_type');
 | 
			
		||||
    db_add_index($table_name, $field_name . '_target_id', array($field_name . '_target_id'));
 | 
			
		||||
 | 
			
		||||
    db_drop_index($revision_name, $field_name . '_target_entity');
 | 
			
		||||
    db_drop_index($revision_name, $field_name . '_target_id');
 | 
			
		||||
    db_drop_field($revision_name, $field_name . '_target_type');
 | 
			
		||||
    db_add_index($revision_name, $field_name . '_target_id', array($field_name . '_target_id'));
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Make the target_id column NOT NULL.
 | 
			
		||||
 */
 | 
			
		||||
function entityreference_update_7002() {
 | 
			
		||||
  if (!module_exists('field_sql_storage')) {
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  foreach (field_info_fields() as $field_name => $field) {
 | 
			
		||||
    if ($field['type'] != 'entityreference') {
 | 
			
		||||
      // Not an entity reference field.
 | 
			
		||||
      continue;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ($field['storage']['type'] !== 'field_sql_storage') {
 | 
			
		||||
      // Field doesn't use SQL storage, we cannot modify the schema.
 | 
			
		||||
      continue;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $table_name = _field_sql_storage_tablename($field);
 | 
			
		||||
    $revision_name = _field_sql_storage_revision_tablename($field);
 | 
			
		||||
 | 
			
		||||
    db_change_field($table_name, $field_name . '_target_id', $field_name . '_target_id', array(
 | 
			
		||||
      'description' => 'The id of the target entity.',
 | 
			
		||||
      'type' => 'int',
 | 
			
		||||
      'unsigned' => TRUE,
 | 
			
		||||
      'not null' => TRUE,
 | 
			
		||||
    ));
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,27 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @file
 | 
			
		||||
 * Support for processing entity reference fields in Migrate.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Implement hook_migrate_api().
 | 
			
		||||
 */
 | 
			
		||||
function entityreference_migrate_api() {
 | 
			
		||||
  return array(
 | 
			
		||||
    'api' => 2,
 | 
			
		||||
    'field_handlers' => array('MigrateEntityReferenceFieldHandler'),
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class MigrateEntityReferenceFieldHandler extends MigrateSimpleFieldHandler {
 | 
			
		||||
  public function __construct() {
 | 
			
		||||
    parent::__construct(array(
 | 
			
		||||
      'value_key' => 'target_id',
 | 
			
		||||
      'skip_empty' => TRUE,
 | 
			
		||||
    ));
 | 
			
		||||
 | 
			
		||||
    $this->registerTypes(array('entityreference'));
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
name = Entity Reference Behavior Example
 | 
			
		||||
description = Provides some example code for implementing Entity Reference behaviors.
 | 
			
		||||
core = 7.x
 | 
			
		||||
package = Fields
 | 
			
		||||
dependencies[] = entityreference
 | 
			
		||||
 | 
			
		||||
; Information added by drupal.org packaging script on 2012-11-18
 | 
			
		||||
version = "7.x-1.0"
 | 
			
		||||
core = "7.x"
 | 
			
		||||
project = "entityreference"
 | 
			
		||||
datestamp = "1353230808"
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,15 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @file
 | 
			
		||||
 * Example module to demonstrate Entity reference behavior handlers.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Implements hook_ctools_plugin_directory().
 | 
			
		||||
 */
 | 
			
		||||
function entityreference_behavior_example_ctools_plugin_directory($module, $plugin) {
 | 
			
		||||
  if ($module == 'entityreference') {
 | 
			
		||||
    return 'plugins/' . $plugin;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,31 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
class EntityReferenceFieldBehaviorExample extends EntityReference_BehaviorHandler_Abstract {
 | 
			
		||||
 | 
			
		||||
  public function load($entity_type, $entities, $field, $instances, $langcode, &$items) {
 | 
			
		||||
    drupal_set_message(t('Do something on load!'));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function insert($entity_type, $entity, $field, $instance, $langcode, &$items) {
 | 
			
		||||
    drupal_set_message(t('Do something on insert!'));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function update($entity_type, $entity, $field, $instance, $langcode, &$items) {
 | 
			
		||||
    drupal_set_message(t('Do something on update!'));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function delete($entity_type, $entity, $field, $instance, $langcode, &$items) {
 | 
			
		||||
    drupal_set_message(t('Do something on delete!'));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Generate a settings form for this handler.
 | 
			
		||||
   */
 | 
			
		||||
  public function settingsForm($field, $instance) {
 | 
			
		||||
    $form['test_field'] = array(
 | 
			
		||||
      '#type' => 'checkbox',
 | 
			
		||||
      '#title' => t('Field behavior setting'),
 | 
			
		||||
    );
 | 
			
		||||
    return $form;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,31 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
class EntityReferenceInstanceBehaviorExample extends EntityReference_BehaviorHandler_Abstract {
 | 
			
		||||
 | 
			
		||||
  public function load($entity_type, $entities, $field, $instances, $langcode, &$items) {
 | 
			
		||||
    drupal_set_message(t('Do something on load, on the instance level!'));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function insert($entity_type, $entity, $field, $instance, $langcode, &$items) {
 | 
			
		||||
    drupal_set_message(t('Do something on insert, on the instance level!'));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function update($entity_type, $entity, $field, $instance, $langcode, &$items) {
 | 
			
		||||
    drupal_set_message(t('Do something on update, on the instance level!'));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function delete($entity_type, $entity, $field, $instance, $langcode, &$items) {
 | 
			
		||||
    drupal_set_message(t('Do something on delete, on the instance level!'));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Generate a settings form for this handler.
 | 
			
		||||
   */
 | 
			
		||||
  public function settingsForm($field, $instance) {
 | 
			
		||||
    $form['test_instance'] = array(
 | 
			
		||||
      '#type' => 'checkbox',
 | 
			
		||||
      '#title' => t('Instance behavior setting'),
 | 
			
		||||
    );
 | 
			
		||||
    return $form;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,8 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
$plugin = array(
 | 
			
		||||
  'title' => t('Test behavior'),
 | 
			
		||||
  'class' => 'EntityReferenceFieldBehaviorExample',
 | 
			
		||||
  'weight' => 10,
 | 
			
		||||
  'behavior type' => 'field',
 | 
			
		||||
);
 | 
			
		||||
@@ -0,0 +1,8 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
$plugin = array(
 | 
			
		||||
  'title' => t('Test instance behavior'),
 | 
			
		||||
  'class' => 'EntityReferenceInstanceBehaviorExample',
 | 
			
		||||
  'weight' => 10,
 | 
			
		||||
  'behavior type' => 'instance',
 | 
			
		||||
);
 | 
			
		||||
@@ -0,0 +1,5 @@
 | 
			
		||||
1354482-er-user-roles-19.patch
 | 
			
		||||
http://drupal.org/node/1354482
 | 
			
		||||
 | 
			
		||||
patch-entityreference-7.x.patch
 | 
			
		||||
http://drupal.org/node/1691612
 | 
			
		||||
@@ -0,0 +1,18 @@
 | 
			
		||||
diff --git a/views/entityreference_plugin_display.inc b/views/entityreference_plugin_display.inc
 | 
			
		||||
index 1fc6450..b9a956d 100644
 | 
			
		||||
--- a/views/entityreference_plugin_display.inc
 | 
			
		||||
+++ b/views/entityreference_plugin_display.inc
 | 
			
		||||
@@ -76,7 +76,12 @@
 | 
			
		||||
       foreach ($style_options['search_fields'] as $field_alias) {
 | 
			
		||||
         if (!empty($field_alias)) {
 | 
			
		||||
           // Get the table and field names for the checked field
 | 
			
		||||
-          $field = $this->view->query->fields[$this->view->field[$field_alias]->field_alias];
 | 
			
		||||
+          if (empty($this->view->field[$field_alias]->field_info)) 
 | 
			
		||||
+            $field = $this->view->query->fields[$this->view->field[$field_alias]->field_alias];
 | 
			
		||||
+          else {
 | 
			
		||||
+            $this->view->query->add_field($this->view->field[$field_alias]->options['table'], $this->view->field[$field_alias]->real_field, $this->view->field[$field_alias]->options['field'], array());
 | 
			
		||||
+            $field = $this->view->query->fields[$this->view->field[$field_alias]->options['field']];
 | 
			
		||||
+          }
 | 
			
		||||
           // Add an OR condition for the field
 | 
			
		||||
           $conditions->condition($field['table'] . '.' . $field['field'], $value, 'LIKE');
 | 
			
		||||
         }
 | 
			
		||||
@@ -0,0 +1,189 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @file
 | 
			
		||||
 * CTools plugin class for the taxonomy-index behavior.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Extends an entityreference field to maintain its references to taxonomy terms
 | 
			
		||||
 * in the {taxonomy_index} table.
 | 
			
		||||
 *
 | 
			
		||||
 * Note, unlike entityPostInsert() and entityPostUpdate(), entityDelete()
 | 
			
		||||
 * is not needed as cleanup is performed by taxonomy module in
 | 
			
		||||
 * taxonomy_delete_node_index().
 | 
			
		||||
 */
 | 
			
		||||
class EntityReferenceBehavior_TaxonomyIndex extends EntityReference_BehaviorHandler_Abstract {
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Overrides EntityReference_BehaviorHandler_Abstract::access().
 | 
			
		||||
   *
 | 
			
		||||
   * Ensure that it is only enabled for ER instances on nodes targeting
 | 
			
		||||
   * terms, and the core variable to maintain index is enabled.
 | 
			
		||||
   */
 | 
			
		||||
  public function access($field, $instance) {
 | 
			
		||||
    if ($instance['entity_type'] != 'node' || $field['settings']['target_type'] != 'taxonomy_term') {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ($field['storage']['type'] !== 'field_sql_storage') {
 | 
			
		||||
      // Field doesn't use SQL storage.
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return variable_get('taxonomy_maintain_index_table', TRUE);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Overrides EntityReference_BehaviorHandler_Abstract::entityPostInsert().
 | 
			
		||||
   *
 | 
			
		||||
   * Runs after hook_node_insert() used by taxonomy module.
 | 
			
		||||
   */
 | 
			
		||||
  public function entityPostInsert($entity_type, $entity, $field, $instance) {
 | 
			
		||||
    if ($entity_type != 'node') {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $this->buildNodeIndex($entity);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Overrides EntityReference_BehaviorHandler_Abstract::entityPostUpdate().
 | 
			
		||||
   *
 | 
			
		||||
   * Runs after hook_node_update() used by taxonomy module.
 | 
			
		||||
   */
 | 
			
		||||
  public function entityPostUpdate($entity_type, $entity, $field, $instance) {
 | 
			
		||||
    if ($entity_type != 'node') {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $this->buildNodeIndex($entity);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Builds and inserts taxonomy index entries for a given node.
 | 
			
		||||
   *
 | 
			
		||||
   * The index lists all terms that are related to a given node entity, and is
 | 
			
		||||
   * therefore maintained at the entity level.
 | 
			
		||||
   *
 | 
			
		||||
   * @param $node
 | 
			
		||||
   *   The node object.
 | 
			
		||||
   *
 | 
			
		||||
   * @see taxonomy_build_node_index()
 | 
			
		||||
   */
 | 
			
		||||
  protected function buildNodeIndex($node) {
 | 
			
		||||
    // We maintain a denormalized table of term/node relationships, containing
 | 
			
		||||
    // only data for current, published nodes.
 | 
			
		||||
    $status = NULL;
 | 
			
		||||
    if (variable_get('taxonomy_maintain_index_table', TRUE)) {
 | 
			
		||||
      // If a node property is not set in the node object when node_save() is
 | 
			
		||||
      // called, the old value from $node->original is used.
 | 
			
		||||
      if (!empty($node->original)) {
 | 
			
		||||
        $status = (int)(!empty($node->status) || (!isset($node->status) && !empty($node->original->status)));
 | 
			
		||||
        $sticky = (int)(!empty($node->sticky) || (!isset($node->sticky) && !empty($node->original->sticky)));
 | 
			
		||||
      }
 | 
			
		||||
      else {
 | 
			
		||||
        $status = (int)(!empty($node->status));
 | 
			
		||||
        $sticky = (int)(!empty($node->sticky));
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    // We only maintain the taxonomy index for published nodes.
 | 
			
		||||
    if ($status) {
 | 
			
		||||
      // Collect a unique list of all the term IDs from all node fields.
 | 
			
		||||
      $tid_all = array();
 | 
			
		||||
      foreach (field_info_instances('node', $node->type) as $instance) {
 | 
			
		||||
        $field_name = $instance['field_name'];
 | 
			
		||||
        $field = field_info_field($field_name);
 | 
			
		||||
        if (!empty($field['settings']['target_type']) && $field['settings']['target_type'] == 'taxonomy_term' && $field['storage']['type'] == 'field_sql_storage') {
 | 
			
		||||
          // If a field value is not set in the node object when node_save() is
 | 
			
		||||
          // called, the old value from $node->original is used.
 | 
			
		||||
          if (isset($node->{$field_name})) {
 | 
			
		||||
            $items = $node->{$field_name};
 | 
			
		||||
          }
 | 
			
		||||
          elseif (isset($node->original->{$field_name})) {
 | 
			
		||||
            $items = $node->original->{$field_name};
 | 
			
		||||
          }
 | 
			
		||||
          else {
 | 
			
		||||
            continue;
 | 
			
		||||
          }
 | 
			
		||||
          foreach (field_available_languages('node', $field) as $langcode) {
 | 
			
		||||
            if (!empty($items[$langcode])) {
 | 
			
		||||
              foreach ($items[$langcode] as $item) {
 | 
			
		||||
                $tid_all[$item['target_id']] = $item['target_id'];
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Re-calculate the terms added in taxonomy_build_node_index() so
 | 
			
		||||
        // we can optimize database queries.
 | 
			
		||||
        $original_tid_all = array();
 | 
			
		||||
        if ($field['module'] == 'taxonomy' && $field['storage']['type'] == 'field_sql_storage') {
 | 
			
		||||
          // If a field value is not set in the node object when node_save() is
 | 
			
		||||
          // called, the old value from $node->original is used.
 | 
			
		||||
          if (isset($node->{$field_name})) {
 | 
			
		||||
            $items = $node->{$field_name};
 | 
			
		||||
          }
 | 
			
		||||
          elseif (isset($node->original->{$field_name})) {
 | 
			
		||||
            $items = $node->original->{$field_name};
 | 
			
		||||
          }
 | 
			
		||||
          else {
 | 
			
		||||
            continue;
 | 
			
		||||
          }
 | 
			
		||||
          foreach (field_available_languages('node', $field) as $langcode) {
 | 
			
		||||
            if (!empty($items[$langcode])) {
 | 
			
		||||
              foreach ($items[$langcode] as $item) {
 | 
			
		||||
                $original_tid_all[$item['tid']] = $item['tid'];
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // Insert index entries for all the node's terms, that were not
 | 
			
		||||
      // already inserted in taxonomy_build_node_index().
 | 
			
		||||
      $tid_all = array_diff($tid_all, $original_tid_all);
 | 
			
		||||
 | 
			
		||||
      // Insert index entries for all the node's terms.
 | 
			
		||||
      if (!empty($tid_all)) {
 | 
			
		||||
        $query = db_insert('taxonomy_index')->fields(array('nid', 'tid', 'sticky', 'created'));
 | 
			
		||||
        foreach ($tid_all as $tid) {
 | 
			
		||||
          $query->values(array(
 | 
			
		||||
            'nid' => $node->nid,
 | 
			
		||||
            'tid' => $tid,
 | 
			
		||||
            'sticky' => $sticky,
 | 
			
		||||
            'created' => $node->created,
 | 
			
		||||
          ));
 | 
			
		||||
        }
 | 
			
		||||
        $query->execute();
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Overrides EntityReference_BehaviorHandler_Abstract::settingsForm().
 | 
			
		||||
   */
 | 
			
		||||
  public function settingsForm($field, $instance) {
 | 
			
		||||
    $form = array();
 | 
			
		||||
    $target = $field['settings']['target_type'];
 | 
			
		||||
    if ($target != 'taxonomy_term') {
 | 
			
		||||
      $form['ti-on-terms'] = array(
 | 
			
		||||
        '#markup' => t('This behavior can only be set when the target type is taxonomy_term, but the target of this field is %target.', array('%target' => $target)),
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $entity_type = $instance['entity_type'];
 | 
			
		||||
    if ($entity_type != 'node') {
 | 
			
		||||
      $form['ti-on-nodes'] = array(
 | 
			
		||||
        '#markup' => t('This behavior can only be set when the entity type is node, but the entity type of this instance is %type.', array('%type' => $entity_type)),
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!variable_get('taxonomy_maintain_index_table', TRUE)) {
 | 
			
		||||
      $form['ti-disabled'] = array(
 | 
			
		||||
        '#markup' => t('This core variable "taxonomy_maintain_index_table" is disabled.'),
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
    return $form;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,18 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
class EntityReferenceBehavior_ViewsFilterSelect extends EntityReference_BehaviorHandler_Abstract {
 | 
			
		||||
 | 
			
		||||
  public function views_data_alter(&$data, $field) {
 | 
			
		||||
    $entity_info = entity_get_info($field['settings']['target_type']);
 | 
			
		||||
    $field_name = $field['field_name'] . '_target_id';
 | 
			
		||||
    foreach ($data as $table_name => &$table_data) {
 | 
			
		||||
      if (isset($table_data[$field_name])) {
 | 
			
		||||
        // Set the entity id filter to use the in_operator handler with our
 | 
			
		||||
        // own callback to return the values.
 | 
			
		||||
        $table_data[$field_name]['filter']['handler'] = 'views_handler_filter_in_operator';
 | 
			
		||||
        $table_data[$field_name]['filter']['options callback'] = 'entityreference_views_handler_options_list';
 | 
			
		||||
        $table_data[$field_name]['filter']['options arguments'] = array($field['field_name']);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,214 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Additional behaviors for a Entity Reference field.
 | 
			
		||||
 *
 | 
			
		||||
 * Implementations that wish to provide an implementation of this should
 | 
			
		||||
 * register it using CTools' plugin system.
 | 
			
		||||
 */
 | 
			
		||||
interface EntityReference_BehaviorHandler {
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Constructor for the behavior.
 | 
			
		||||
   *
 | 
			
		||||
   * @param $behavior
 | 
			
		||||
   *   The name of the behavior plugin.
 | 
			
		||||
   */
 | 
			
		||||
  public function __construct($behavior);
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Alter the field schema.
 | 
			
		||||
   *
 | 
			
		||||
   * @see hook_field_schema()
 | 
			
		||||
   */
 | 
			
		||||
  public function schema_alter(&$schema, $field);
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Alter the properties information of a field instance.
 | 
			
		||||
   *
 | 
			
		||||
   * @see entity_hook_field_info()
 | 
			
		||||
   */
 | 
			
		||||
  public function property_info_alter(&$info, $entity_type, $field, $instance, $field_type);
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Alter the views data of a field.
 | 
			
		||||
   *
 | 
			
		||||
   * @see entityreference_field_views_data()
 | 
			
		||||
   */
 | 
			
		||||
  public function views_data_alter(&$data, $field);
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Act on loading entity reference fields of entities.
 | 
			
		||||
   *
 | 
			
		||||
   * @see hook_field_load()
 | 
			
		||||
   */
 | 
			
		||||
  public function load($entity_type, $entities, $field, $instances, $langcode, &$items);
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Alter the empty status of a field item.
 | 
			
		||||
   *
 | 
			
		||||
   * @see hook_field_is_empty()
 | 
			
		||||
   */
 | 
			
		||||
  public function is_empty_alter(&$empty, $item, $field);
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Act on validating an entity reference field.
 | 
			
		||||
   *
 | 
			
		||||
   * @see hook_field_validate()
 | 
			
		||||
   */
 | 
			
		||||
  public function validate($entity_type, $entity, $field, $instance, $langcode, $items, &$errors);
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Act on presaving an entity reference field.
 | 
			
		||||
   *
 | 
			
		||||
   * @see hook_field_presave()
 | 
			
		||||
   */
 | 
			
		||||
  public function presave($entity_type, $entity, $field, $instance, $langcode, &$items);
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Act before inserting an entity reference field.
 | 
			
		||||
   *
 | 
			
		||||
   * @see hook_field_insert()
 | 
			
		||||
   */
 | 
			
		||||
  public function insert($entity_type, $entity, $field, $instance, $langcode, &$items);
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Act after inserting an entity reference field.
 | 
			
		||||
   *
 | 
			
		||||
   * @see hook_field_attach_insert()
 | 
			
		||||
   */
 | 
			
		||||
  public function postInsert($entity_type, $entity, $field, $instance);
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Act before updating an entity reference field.
 | 
			
		||||
   *
 | 
			
		||||
   * @see hook_field_update()
 | 
			
		||||
   */
 | 
			
		||||
  public function update($entity_type, $entity, $field, $instance, $langcode, &$items);
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Act after updating an entity reference field.
 | 
			
		||||
   *
 | 
			
		||||
   * @see hook_field_attach_update()
 | 
			
		||||
   */
 | 
			
		||||
  public function postUpdate($entity_type, $entity, $field, $instance);
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Act before deleting an entity with an entity reference field.
 | 
			
		||||
   *
 | 
			
		||||
   * @see hook_field_delete()
 | 
			
		||||
   */
 | 
			
		||||
  public function delete($entity_type, $entity, $field, $instance, $langcode, &$items);
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Act after deleting an entity with an entity reference field.
 | 
			
		||||
   *
 | 
			
		||||
   * @see hook_field_attach_delete()
 | 
			
		||||
   */
 | 
			
		||||
  public function postDelete($entity_type, $entity, $field, $instance);
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Act after inserting an entity.
 | 
			
		||||
   *
 | 
			
		||||
   * @see hook_entity_insert()
 | 
			
		||||
   */
 | 
			
		||||
  public function entityPostInsert($entity_type, $entity, $field, $instance);
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Act after updating an entity.
 | 
			
		||||
   *
 | 
			
		||||
   * @see hook_entity_update()
 | 
			
		||||
   */
 | 
			
		||||
  public function entityPostUpdate($entity_type, $entity, $field, $instance);
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Act after deleting an entity.
 | 
			
		||||
   *
 | 
			
		||||
   * @see hook_entity_delete()
 | 
			
		||||
   */
 | 
			
		||||
  public function entityPostDelete($entity_type, $entity, $field, $instance);
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Generate a settings form for this handler.
 | 
			
		||||
   */
 | 
			
		||||
  public function settingsForm($field, $instance);
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Determine if handler should appear.
 | 
			
		||||
   */
 | 
			
		||||
  public function access($field, $instance);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * An abstract implementation of EntityReference_BehaviorHandler.
 | 
			
		||||
 */
 | 
			
		||||
abstract class EntityReference_BehaviorHandler_Abstract implements EntityReference_BehaviorHandler {
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * The name of the behavior plugin.
 | 
			
		||||
   */
 | 
			
		||||
  protected $behavior;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * The plugin definition.
 | 
			
		||||
   */
 | 
			
		||||
  protected $plugin;
 | 
			
		||||
 | 
			
		||||
  public function __construct($behavior) {
 | 
			
		||||
    $this->behavior = $behavior;
 | 
			
		||||
 | 
			
		||||
    ctools_include('plugins');
 | 
			
		||||
    $plugin = ctools_get_plugins('entityreference', 'behavior', $behavior);
 | 
			
		||||
    $this->plugin = $plugin;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function schema_alter(&$schema, $field) {}
 | 
			
		||||
 | 
			
		||||
  public function property_info_alter(&$info, $entity_type, $field, $instance, $field_type) {}
 | 
			
		||||
 | 
			
		||||
  public function views_data_alter(&$data, $field) {}
 | 
			
		||||
 | 
			
		||||
  public function load($entity_type, $entities, $field, $instances, $langcode, &$items) {}
 | 
			
		||||
 | 
			
		||||
  public function is_empty_alter(&$empty, $item, $field) {}
 | 
			
		||||
 | 
			
		||||
  public function validate($entity_type, $entity, $field, $instance, $langcode, $items, &$errors) {}
 | 
			
		||||
 | 
			
		||||
  public function presave($entity_type, $entity, $field, $instance, $langcode, &$items) {}
 | 
			
		||||
 | 
			
		||||
  public function insert($entity_type, $entity, $field, $instance, $langcode, &$items) {}
 | 
			
		||||
 | 
			
		||||
  public function postInsert($entity_type, $entity, $field, $instance) {}
 | 
			
		||||
 | 
			
		||||
  public function update($entity_type, $entity, $field, $instance, $langcode, &$items) {}
 | 
			
		||||
 | 
			
		||||
  public function postUpdate($entity_type, $entity, $field, $instance) {}
 | 
			
		||||
 | 
			
		||||
  public function delete($entity_type, $entity, $field, $instance, $langcode, &$items) {}
 | 
			
		||||
 | 
			
		||||
  public function postDelete($entity_type, $entity, $field, $instance) {}
 | 
			
		||||
 | 
			
		||||
  public function entityPostInsert($entity_type, $entity, $field, $instance) {}
 | 
			
		||||
 | 
			
		||||
  public function entityPostUpdate($entity_type, $entity, $field, $instance) {}
 | 
			
		||||
 | 
			
		||||
  public function entityPostDelete($entity_type, $entity, $field, $instance) {}
 | 
			
		||||
 | 
			
		||||
  public function settingsForm($field, $instance) {}
 | 
			
		||||
 | 
			
		||||
  public function access($field, $instance) {
 | 
			
		||||
    return TRUE;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A broken implementation of EntityReference_BehaviorHandler.
 | 
			
		||||
 */
 | 
			
		||||
class EntityReference_BehaviorHandler_Broken extends EntityReference_BehaviorHandler_Abstract {
 | 
			
		||||
  public function settingsForm($field, $instance) {
 | 
			
		||||
    $form['behavior_handler'] = array(
 | 
			
		||||
      '#markup' => t('The selected behavior handler is broken.'),
 | 
			
		||||
    );
 | 
			
		||||
    return $form;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,16 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @file
 | 
			
		||||
 * CTools plugin declaration for taxonomy-index behavior.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
if (module_exists('taxonomy')) {
 | 
			
		||||
  $plugin = array(
 | 
			
		||||
    'title' => t('Taxonomy index'),
 | 
			
		||||
    'description' => t('Include the term references created by instances of this field carried by node entities in the core {taxonomy_index} table. This will allow various modules to handle them like core term_reference fields.'),
 | 
			
		||||
    'class' => 'EntityReferenceBehavior_TaxonomyIndex',
 | 
			
		||||
    'behavior type' => 'instance',
 | 
			
		||||
    'force enabled' => TRUE,
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,10 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
if (module_exists('views')) {
 | 
			
		||||
  $plugin = array(
 | 
			
		||||
    'title' => t('Render Views filters as select list'),
 | 
			
		||||
    'description' => t('Provides a select list for Views filters on this field. This should not be used when there are over 100 entities, as it might cause an out of memory error.'),
 | 
			
		||||
    'class' => 'EntityReferenceBehavior_ViewsFilterSelect',
 | 
			
		||||
    'behavior type' => 'field',
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,599 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A generic Entity handler.
 | 
			
		||||
 *
 | 
			
		||||
 * The generic base implementation has a variety of overrides to workaround
 | 
			
		||||
 * core's largely deficient entity handling.
 | 
			
		||||
 */
 | 
			
		||||
class EntityReference_SelectionHandler_Generic implements EntityReference_SelectionHandler {
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Implements EntityReferenceHandler::getInstance().
 | 
			
		||||
   */
 | 
			
		||||
  public static function getInstance($field, $instance = NULL, $entity_type = NULL, $entity = NULL) {
 | 
			
		||||
    $target_entity_type = $field['settings']['target_type'];
 | 
			
		||||
 | 
			
		||||
    // Check if the entity type does exist and has a base table.
 | 
			
		||||
    $entity_info = entity_get_info($target_entity_type);
 | 
			
		||||
    if (empty($entity_info['base table'])) {
 | 
			
		||||
      return EntityReference_SelectionHandler_Broken::getInstance($field, $instance);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (class_exists($class_name = 'EntityReference_SelectionHandler_Generic_' . $target_entity_type)) {
 | 
			
		||||
      return new $class_name($field, $instance, $entity_type, $entity);
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
      return new EntityReference_SelectionHandler_Generic($field, $instance, $entity_type, $entity);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected function __construct($field, $instance = NULL, $entity_type = NULL, $entity = NULL) {
 | 
			
		||||
    $this->field = $field;
 | 
			
		||||
    $this->instance = $instance;
 | 
			
		||||
    $this->entity_type = $entity_type;
 | 
			
		||||
    $this->entity = $entity;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Implements EntityReferenceHandler::settingsForm().
 | 
			
		||||
   */
 | 
			
		||||
  public static function settingsForm($field, $instance) {
 | 
			
		||||
    $entity_info = entity_get_info($field['settings']['target_type']);
 | 
			
		||||
 | 
			
		||||
    // Merge-in default values.
 | 
			
		||||
    $field['settings']['handler_settings'] += array(
 | 
			
		||||
      'target_bundles' => array(),
 | 
			
		||||
      'sort' => array(
 | 
			
		||||
        'type' => 'none',
 | 
			
		||||
      )
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    if (!empty($entity_info['entity keys']['bundle'])) {
 | 
			
		||||
      $bundles = array();
 | 
			
		||||
      foreach ($entity_info['bundles'] as $bundle_name => $bundle_info) {
 | 
			
		||||
        $bundles[$bundle_name] = $bundle_info['label'];
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      $form['target_bundles'] = array(
 | 
			
		||||
        '#type' => 'checkboxes',
 | 
			
		||||
        '#title' => t('Target bundles'),
 | 
			
		||||
        '#options' => $bundles,
 | 
			
		||||
        '#default_value' => $field['settings']['handler_settings']['target_bundles'],
 | 
			
		||||
        '#size' => 6,
 | 
			
		||||
        '#multiple' => TRUE,
 | 
			
		||||
        '#description' => t('The bundles of the entity type that can be referenced. Optional, leave empty for all bundles.'),
 | 
			
		||||
        '#element_validate' => array('_entityreference_element_validate_filter'),
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
      $form['target_bundles'] = array(
 | 
			
		||||
        '#type' => 'value',
 | 
			
		||||
        '#value' => array(),
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $form['sort']['type'] = array(
 | 
			
		||||
      '#type' => 'select',
 | 
			
		||||
      '#title' => t('Sort by'),
 | 
			
		||||
      '#options' => array(
 | 
			
		||||
        'none' => t("Don't sort"),
 | 
			
		||||
        'property' => t('A property of the base table of the entity'),
 | 
			
		||||
        'field' => t('A field attached to this entity'),
 | 
			
		||||
      ),
 | 
			
		||||
      '#ajax' => TRUE,
 | 
			
		||||
      '#limit_validation_errors' => array(),
 | 
			
		||||
      '#default_value' => $field['settings']['handler_settings']['sort']['type'],
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    $form['sort']['settings'] = array(
 | 
			
		||||
      '#type' => 'container',
 | 
			
		||||
      '#attributes' => array('class' => array('entityreference-settings')),
 | 
			
		||||
      '#process' => array('_entityreference_form_process_merge_parent'),
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    if ($field['settings']['handler_settings']['sort']['type'] == 'property') {
 | 
			
		||||
      // Merge-in default values.
 | 
			
		||||
      $field['settings']['handler_settings']['sort'] += array(
 | 
			
		||||
        'property' => NULL,
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      $form['sort']['settings']['property'] = array(
 | 
			
		||||
        '#type' => 'select',
 | 
			
		||||
        '#title' => t('Sort property'),
 | 
			
		||||
        '#required' => TRUE,
 | 
			
		||||
        '#options' => drupal_map_assoc($entity_info['schema_fields_sql']['base table']),
 | 
			
		||||
        '#default_value' => $field['settings']['handler_settings']['sort']['property'],
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
    elseif ($field['settings']['handler_settings']['sort']['type'] == 'field') {
 | 
			
		||||
      // Merge-in default values.
 | 
			
		||||
      $field['settings']['handler_settings']['sort'] += array(
 | 
			
		||||
        'field' => NULL,
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      $fields = array();
 | 
			
		||||
      foreach (field_info_instances($field['settings']['target_type']) as $bundle_name => $bundle_instances) {
 | 
			
		||||
        foreach ($bundle_instances as $instance_name => $instance_info) {
 | 
			
		||||
          $field_info = field_info_field($instance_name);
 | 
			
		||||
          foreach ($field_info['columns'] as $column_name => $column_info) {
 | 
			
		||||
            $fields[$instance_name . ':' . $column_name] = t('@label (column @column)', array('@label' => $instance_info['label'], '@column' => $column_name));
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      $form['sort']['settings']['field'] = array(
 | 
			
		||||
        '#type' => 'select',
 | 
			
		||||
        '#title' => t('Sort field'),
 | 
			
		||||
        '#required' => TRUE,
 | 
			
		||||
        '#options' => $fields,
 | 
			
		||||
        '#default_value' => $field['settings']['handler_settings']['sort']['field'],
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ($field['settings']['handler_settings']['sort']['type'] != 'none') {
 | 
			
		||||
      // Merge-in default values.
 | 
			
		||||
      $field['settings']['handler_settings']['sort'] += array(
 | 
			
		||||
        'direction' => 'ASC',
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      $form['sort']['settings']['direction'] = array(
 | 
			
		||||
        '#type' => 'select',
 | 
			
		||||
        '#title' => t('Sort direction'),
 | 
			
		||||
        '#required' => TRUE,
 | 
			
		||||
        '#options' => array(
 | 
			
		||||
          'ASC' => t('Ascending'),
 | 
			
		||||
          'DESC' => t('Descending'),
 | 
			
		||||
        ),
 | 
			
		||||
        '#default_value' => $field['settings']['handler_settings']['sort']['direction'],
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return $form;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Implements EntityReferenceHandler::getReferencableEntities().
 | 
			
		||||
   */
 | 
			
		||||
  public function getReferencableEntities($match = NULL, $match_operator = 'CONTAINS', $limit = 0) {
 | 
			
		||||
    $options = array();
 | 
			
		||||
    $entity_type = $this->field['settings']['target_type'];
 | 
			
		||||
 | 
			
		||||
    $query = $this->buildEntityFieldQuery($match, $match_operator);
 | 
			
		||||
    if ($limit > 0) {
 | 
			
		||||
      $query->range(0, $limit);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $results = $query->execute();
 | 
			
		||||
 | 
			
		||||
    if (!empty($results[$entity_type])) {
 | 
			
		||||
      $entities = entity_load($entity_type, array_keys($results[$entity_type]));
 | 
			
		||||
      foreach ($entities as $entity_id => $entity) {
 | 
			
		||||
        list(,, $bundle) = entity_extract_ids($entity_type, $entity);
 | 
			
		||||
        $options[$bundle][$entity_id] = check_plain($this->getLabel($entity));
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return $options;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Implements EntityReferenceHandler::countReferencableEntities().
 | 
			
		||||
   */
 | 
			
		||||
  public function countReferencableEntities($match = NULL, $match_operator = 'CONTAINS') {
 | 
			
		||||
    $query = $this->buildEntityFieldQuery($match, $match_operator);
 | 
			
		||||
    return $query
 | 
			
		||||
      ->count()
 | 
			
		||||
      ->execute();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Implements EntityReferenceHandler::validateReferencableEntities().
 | 
			
		||||
   */
 | 
			
		||||
  public function validateReferencableEntities(array $ids) {
 | 
			
		||||
    if ($ids) {
 | 
			
		||||
      $entity_type = $this->field['settings']['target_type'];
 | 
			
		||||
      $query = $this->buildEntityFieldQuery();
 | 
			
		||||
      $query->entityCondition('entity_id', $ids, 'IN');
 | 
			
		||||
      $result = $query->execute();
 | 
			
		||||
      if (!empty($result[$entity_type])) {
 | 
			
		||||
        return array_keys($result[$entity_type]);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return array();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Implements EntityReferenceHandler::validateAutocompleteInput().
 | 
			
		||||
   */
 | 
			
		||||
  public function validateAutocompleteInput($input, &$element, &$form_state, $form) {
 | 
			
		||||
      $entities = $this->getReferencableEntities($input, '=', 6);
 | 
			
		||||
      if (empty($entities)) {
 | 
			
		||||
        // Error if there are no entities available for a required field.
 | 
			
		||||
        form_error($element, t('There are no entities matching "%value"', array('%value' => $input)));
 | 
			
		||||
      }
 | 
			
		||||
      elseif (count($entities) > 5) {
 | 
			
		||||
        // Error if there are more than 5 matching entities.
 | 
			
		||||
        form_error($element, t('Many entities are called %value. Specify the one you want by appending the id in parentheses, like "@value (@id)"', array(
 | 
			
		||||
          '%value' => $input,
 | 
			
		||||
          '@value' => $input,
 | 
			
		||||
          '@id' => key($entities),
 | 
			
		||||
        )));
 | 
			
		||||
      }
 | 
			
		||||
      elseif (count($entities) > 1) {
 | 
			
		||||
        // More helpful error if there are only a few matching entities.
 | 
			
		||||
        $multiples = array();
 | 
			
		||||
        foreach ($entities as $id => $name) {
 | 
			
		||||
          $multiples[] = $name . ' (' . $id . ')';
 | 
			
		||||
        }
 | 
			
		||||
        form_error($element, t('Multiple entities match this reference; "%multiple"', array('%multiple' => implode('", "', $multiples))));
 | 
			
		||||
      }
 | 
			
		||||
      else {
 | 
			
		||||
        // Take the one and only matching entity.
 | 
			
		||||
        return key($entities);
 | 
			
		||||
      }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Build an EntityFieldQuery to get referencable entities.
 | 
			
		||||
   */
 | 
			
		||||
  protected function buildEntityFieldQuery($match = NULL, $match_operator = 'CONTAINS') {
 | 
			
		||||
    $query = new EntityFieldQuery();
 | 
			
		||||
    $query->entityCondition('entity_type', $this->field['settings']['target_type']);
 | 
			
		||||
    if (!empty($this->field['settings']['handler_settings']['target_bundles'])) {
 | 
			
		||||
      $query->entityCondition('bundle', $this->field['settings']['handler_settings']['target_bundles'], 'IN');
 | 
			
		||||
    }
 | 
			
		||||
    if (isset($match)) {
 | 
			
		||||
      $entity_info = entity_get_info($this->field['settings']['target_type']);
 | 
			
		||||
      if (isset($entity_info['entity keys']['label'])) {
 | 
			
		||||
        $query->propertyCondition($entity_info['entity keys']['label'], $match, $match_operator);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Add a generic entity access tag to the query.
 | 
			
		||||
    $query->addTag($this->field['settings']['target_type'] . '_access');
 | 
			
		||||
    $query->addTag('entityreference');
 | 
			
		||||
    $query->addMetaData('field', $this->field);
 | 
			
		||||
    $query->addMetaData('entityreference_selection_handler', $this);
 | 
			
		||||
 | 
			
		||||
    // Add the sort option.
 | 
			
		||||
    if (!empty($this->field['settings']['handler_settings']['sort'])) {
 | 
			
		||||
      $sort_settings = $this->field['settings']['handler_settings']['sort'];
 | 
			
		||||
      if ($sort_settings['type'] == 'property') {
 | 
			
		||||
        $query->propertyOrderBy($sort_settings['property'], $sort_settings['direction']);
 | 
			
		||||
      }
 | 
			
		||||
      elseif ($sort_settings['type'] == 'field') {
 | 
			
		||||
        list($field, $column) = explode(':', $sort_settings['field'], 2);
 | 
			
		||||
        $query->fieldOrderBy($field, $column, $sort_settings['direction']);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return $query;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Implements EntityReferenceHandler::entityFieldQueryAlter().
 | 
			
		||||
   */
 | 
			
		||||
  public function entityFieldQueryAlter(SelectQueryInterface $query) {
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Helper method: pass a query to the alteration system again.
 | 
			
		||||
   *
 | 
			
		||||
   * This allow Entity Reference to add a tag to an existing query, to ask
 | 
			
		||||
   * access control mechanisms to alter it again.
 | 
			
		||||
   */
 | 
			
		||||
  protected function reAlterQuery(SelectQueryInterface $query, $tag, $base_table) {
 | 
			
		||||
    // Save the old tags and metadata.
 | 
			
		||||
    // For some reason, those are public.
 | 
			
		||||
    $old_tags = $query->alterTags;
 | 
			
		||||
    $old_metadata = $query->alterMetaData;
 | 
			
		||||
 | 
			
		||||
    $query->alterTags = array($tag => TRUE);
 | 
			
		||||
    $query->alterMetaData['base_table'] = $base_table;
 | 
			
		||||
    drupal_alter(array('query', 'query_' . $tag), $query);
 | 
			
		||||
 | 
			
		||||
    // Restore the tags and metadata.
 | 
			
		||||
    $query->alterTags = $old_tags;
 | 
			
		||||
    $query->alterMetaData = $old_metadata;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Implements EntityReferenceHandler::getLabel().
 | 
			
		||||
   */
 | 
			
		||||
  public function getLabel($entity) {
 | 
			
		||||
    return entity_label($this->field['settings']['target_type'], $entity);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Ensure a base table exists for the query.
 | 
			
		||||
   *
 | 
			
		||||
   * If we have a field-only query, we want to assure we have a base-table
 | 
			
		||||
   * so we can later alter the query in entityFieldQueryAlter().
 | 
			
		||||
   *
 | 
			
		||||
   * @param $query
 | 
			
		||||
   *   The Select query.
 | 
			
		||||
   *
 | 
			
		||||
   * @return
 | 
			
		||||
   *   The alias of the base-table.
 | 
			
		||||
   */
 | 
			
		||||
  public function ensureBaseTable(SelectQueryInterface $query) {
 | 
			
		||||
    $tables = $query->getTables();
 | 
			
		||||
 | 
			
		||||
    // Check the current base table.
 | 
			
		||||
    foreach ($tables as $table) {
 | 
			
		||||
      if (empty($table['join'])) {
 | 
			
		||||
        $alias = $table['alias'];
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (strpos($alias, 'field_data_') !== 0) {
 | 
			
		||||
      // The existing base-table is the correct one.
 | 
			
		||||
      return $alias;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Join the known base-table.
 | 
			
		||||
    $target_type = $this->field['settings']['target_type'];
 | 
			
		||||
    $entity_info = entity_get_info($target_type);
 | 
			
		||||
    $id = $entity_info['entity keys']['id'];
 | 
			
		||||
    // Return the alias of the table.
 | 
			
		||||
    return $query->innerJoin($target_type, NULL, "$target_type.$id = $alias.entity_id");
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Override for the Node type.
 | 
			
		||||
 *
 | 
			
		||||
 * This only exists to workaround core bugs.
 | 
			
		||||
 */
 | 
			
		||||
class EntityReference_SelectionHandler_Generic_node extends EntityReference_SelectionHandler_Generic {
 | 
			
		||||
  public function entityFieldQueryAlter(SelectQueryInterface $query) {
 | 
			
		||||
    // Adding the 'node_access' tag is sadly insufficient for nodes: core
 | 
			
		||||
    // requires us to also know about the concept of 'published' and
 | 
			
		||||
    // 'unpublished'. We need to do that as long as there are no access control
 | 
			
		||||
    // modules in use on the site. As long as one access control module is there,
 | 
			
		||||
    // it is supposed to handle this check.
 | 
			
		||||
    if (!user_access('bypass node access') && !count(module_implements('node_grants'))) {
 | 
			
		||||
      $base_table = $this->ensureBaseTable($query);
 | 
			
		||||
      $query->condition("$base_table.status", NODE_PUBLISHED);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Override for the User type.
 | 
			
		||||
 *
 | 
			
		||||
 * This only exists to workaround core bugs.
 | 
			
		||||
 */
 | 
			
		||||
class EntityReference_SelectionHandler_Generic_user extends EntityReference_SelectionHandler_Generic {
 | 
			
		||||
  /**
 | 
			
		||||
   * Implements EntityReferenceHandler::settingsForm().
 | 
			
		||||
   */
 | 
			
		||||
  public static function settingsForm($field, $instance) {
 | 
			
		||||
    $settings = $field['settings']['handler_settings'];
 | 
			
		||||
    $form = parent::settingsForm($field, $instance);
 | 
			
		||||
    $form['referenceable_roles'] = array(
 | 
			
		||||
      '#type' => 'checkboxes',
 | 
			
		||||
      '#title' => t('User roles that can be referenced'),
 | 
			
		||||
      '#default_value' => isset($settings['referenceable_roles']) ? array_filter($settings['referenceable_roles']) : array(),
 | 
			
		||||
      '#options' => user_roles(TRUE),
 | 
			
		||||
    );
 | 
			
		||||
    $form['referenceable_status'] = array(
 | 
			
		||||
      '#type' => 'checkboxes',
 | 
			
		||||
      '#title' => t('User status that can be referenced'),
 | 
			
		||||
      '#default_value' => isset($settings['referenceable_status']) ? array_filter($settings['referenceable_status']) : array('active' => 'active'),
 | 
			
		||||
      '#options' => array('active' => t('Active'), 'blocked' => t('Blocked')),
 | 
			
		||||
    );
 | 
			
		||||
    return $form;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function buildEntityFieldQuery($match = NULL, $match_operator = 'CONTAINS') {
 | 
			
		||||
    $query = parent::buildEntityFieldQuery($match, $match_operator);
 | 
			
		||||
 | 
			
		||||
    // The user entity doesn't have a label column.
 | 
			
		||||
    if (isset($match)) {
 | 
			
		||||
      $query->propertyCondition('name', $match, $match_operator);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $field = $this->field;
 | 
			
		||||
    $settings = $field['settings']['handler_settings'];
 | 
			
		||||
    $referenceable_roles = isset($settings['referenceable_roles']) ? array_filter($settings['referenceable_roles']) : array();
 | 
			
		||||
    $referenceable_status = isset($settings['referenceable_status']) ? array_filter($settings['referenceable_status']) : array('active' => 'active');
 | 
			
		||||
 | 
			
		||||
    // If this filter is not filled, use the users access permissions.
 | 
			
		||||
    if (empty($referenceable_status)) {
 | 
			
		||||
      // Adding the 'user_access' tag is sadly insufficient for users: core
 | 
			
		||||
      // requires us to also know about the concept of 'blocked' and 'active'.
 | 
			
		||||
      if (!user_access('administer users')) {
 | 
			
		||||
        $query->propertyCondition('status', 1);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    elseif (count($referenceable_status) == 1) {
 | 
			
		||||
      $values = array('active' => 1, 'blocked' => 0);
 | 
			
		||||
      $query->propertyCondition('status', $values[key($referenceable_status)]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return $query;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function entityFieldQueryAlter(SelectQueryInterface $query) {
 | 
			
		||||
    $conditions = &$query->conditions();
 | 
			
		||||
    if (user_access('administer users')) {
 | 
			
		||||
      // If the user is administrator, we need to make sure to
 | 
			
		||||
      // match the anonymous user, that doesn't actually have a name in the
 | 
			
		||||
      // database.
 | 
			
		||||
      foreach ($conditions as $key => $condition) {
 | 
			
		||||
        if ($key !== '#conjunction' && is_string($condition['field']) && $condition['field'] === 'users.name') {
 | 
			
		||||
          // Remove the condition.
 | 
			
		||||
          unset($conditions[$key]);
 | 
			
		||||
 | 
			
		||||
          // Re-add the condition and a condition on uid = 0 so that we end up
 | 
			
		||||
          // with a query in the form:
 | 
			
		||||
          //    WHERE (name LIKE :name) OR (:anonymous_name LIKE :name AND uid = 0)
 | 
			
		||||
          $or = db_or();
 | 
			
		||||
          $or->condition($condition['field'], $condition['value'], $condition['operator']);
 | 
			
		||||
          // Sadly, the Database layer doesn't allow us to build a condition
 | 
			
		||||
          // in the form ':placeholder = :placeholder2', because the 'field'
 | 
			
		||||
          // part of a condition is always escaped.
 | 
			
		||||
          // As a (cheap) workaround, we separately build a condition with no
 | 
			
		||||
          // field, and concatenate the field and the condition separately.
 | 
			
		||||
          $value_part = db_and();
 | 
			
		||||
          $value_part->condition('anonymous_name', $condition['value'], $condition['operator']);
 | 
			
		||||
          $value_part->compile(Database::getConnection(), $query);
 | 
			
		||||
          $or->condition(db_and()
 | 
			
		||||
            ->where(str_replace('anonymous_name', ':anonymous_name', (string) $value_part), $value_part->arguments() + array(':anonymous_name' => format_username(user_load(0))))
 | 
			
		||||
            ->condition('users.uid', 0)
 | 
			
		||||
          );
 | 
			
		||||
          $query->condition($or);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $field = $this->field;
 | 
			
		||||
    $settings = $field['settings']['handler_settings'];
 | 
			
		||||
    $referenceable_roles = isset($settings['referenceable_roles']) ? array_filter($settings['referenceable_roles']) : array();
 | 
			
		||||
    if (!$referenceable_roles || !empty($referenceable_roles[DRUPAL_AUTHENTICATED_RID])) {
 | 
			
		||||
      // Return early if "authenticated user" choosen.
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!isset($referenceable_roles[DRUPAL_AUTHENTICATED_RID])) {
 | 
			
		||||
      $query->join('users_roles', 'users_roles', 'users.uid = users_roles.uid');
 | 
			
		||||
      $query->condition('users_roles.rid', array_keys($referenceable_roles), 'IN');
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Override for the Comment type.
 | 
			
		||||
 *
 | 
			
		||||
 * This only exists to workaround core bugs.
 | 
			
		||||
 */
 | 
			
		||||
class EntityReference_SelectionHandler_Generic_comment extends EntityReference_SelectionHandler_Generic {
 | 
			
		||||
  public function entityFieldQueryAlter(SelectQueryInterface $query) {
 | 
			
		||||
    // Adding the 'comment_access' tag is sadly insufficient for comments: core
 | 
			
		||||
    // requires us to also know about the concept of 'published' and
 | 
			
		||||
    // 'unpublished'.
 | 
			
		||||
    if (!user_access('administer comments')) {
 | 
			
		||||
      $base_table = $this->ensureBaseTable($query);
 | 
			
		||||
      $query->condition("$base_table.status", COMMENT_PUBLISHED);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // The Comment module doesn't implement any proper comment access,
 | 
			
		||||
    // and as a consequence doesn't make sure that comments cannot be viewed
 | 
			
		||||
    // when the user doesn't have access to the node.
 | 
			
		||||
    $tables = $query->getTables();
 | 
			
		||||
    $base_table = key($tables);
 | 
			
		||||
    $node_alias = $query->innerJoin('node', 'n', '%alias.nid = ' . $base_table . '.nid');
 | 
			
		||||
    // Pass the query to the node access control.
 | 
			
		||||
    $this->reAlterQuery($query, 'node_access', $node_alias);
 | 
			
		||||
 | 
			
		||||
    // Alas, the comment entity exposes a bundle, but doesn't have a bundle column
 | 
			
		||||
    // in the database. We have to alter the query ourself to go fetch the
 | 
			
		||||
    // bundle.
 | 
			
		||||
    $conditions = &$query->conditions();
 | 
			
		||||
    foreach ($conditions as $key => &$condition) {
 | 
			
		||||
      if ($key !== '#conjunction' && is_string($condition['field']) && $condition['field'] === 'node_type') {
 | 
			
		||||
        $condition['field'] = $node_alias . '.type';
 | 
			
		||||
        foreach ($condition['value'] as &$value) {
 | 
			
		||||
          if (substr($value, 0, 13) == 'comment_node_') {
 | 
			
		||||
            $value = substr($value, 13);
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Passing the query to node_query_node_access_alter() is sadly
 | 
			
		||||
    // insufficient for nodes.
 | 
			
		||||
    // @see EntityReferenceHandler_node::entityFieldQueryAlter()
 | 
			
		||||
    if (!user_access('bypass node access') && !count(module_implements('node_grants'))) {
 | 
			
		||||
      $query->condition($node_alias . '.status', 1);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Override for the File type.
 | 
			
		||||
 *
 | 
			
		||||
 * This only exists to workaround core bugs.
 | 
			
		||||
 */
 | 
			
		||||
class EntityReference_SelectionHandler_Generic_file extends EntityReference_SelectionHandler_Generic {
 | 
			
		||||
  public function entityFieldQueryAlter(SelectQueryInterface $query) {
 | 
			
		||||
    // Core forces us to know about 'permanent' vs. 'temporary' files.
 | 
			
		||||
    $tables = $query->getTables();
 | 
			
		||||
    $base_table = key($tables);
 | 
			
		||||
    $query->condition('status', FILE_STATUS_PERMANENT);
 | 
			
		||||
 | 
			
		||||
    // Access control to files is a very difficult business. For now, we are not
 | 
			
		||||
    // going to give it a shot.
 | 
			
		||||
    // @todo: fix this when core access control is less insane.
 | 
			
		||||
    return $query;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function getLabel($entity) {
 | 
			
		||||
    // The file entity doesn't have a label. More over, the filename is
 | 
			
		||||
    // sometimes empty, so use the basename in that case.
 | 
			
		||||
    return $entity->filename !== '' ? $entity->filename : basename($entity->uri);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Override for the Taxonomy term type.
 | 
			
		||||
 *
 | 
			
		||||
 * This only exists to workaround core bugs.
 | 
			
		||||
 */
 | 
			
		||||
class EntityReference_SelectionHandler_Generic_taxonomy_term extends EntityReference_SelectionHandler_Generic {
 | 
			
		||||
  public function entityFieldQueryAlter(SelectQueryInterface $query) {
 | 
			
		||||
    // The Taxonomy module doesn't implement any proper taxonomy term access,
 | 
			
		||||
    // and as a consequence doesn't make sure that taxonomy terms cannot be viewed
 | 
			
		||||
    // when the user doesn't have access to the vocabulary.
 | 
			
		||||
    $base_table = $this->ensureBaseTable($query);
 | 
			
		||||
    $vocabulary_alias = $query->innerJoin('taxonomy_vocabulary', 'n', '%alias.vid = ' . $base_table . '.vid');
 | 
			
		||||
    $query->addMetadata('base_table', $vocabulary_alias);
 | 
			
		||||
    // Pass the query to the taxonomy access control.
 | 
			
		||||
    $this->reAlterQuery($query, 'taxonomy_vocabulary_access', $vocabulary_alias);
 | 
			
		||||
 | 
			
		||||
    // Also, the taxonomy term entity exposes a bundle, but doesn't have a bundle
 | 
			
		||||
    // column in the database. We have to alter the query ourself to go fetch
 | 
			
		||||
    // the bundle.
 | 
			
		||||
    $conditions = &$query->conditions();
 | 
			
		||||
    foreach ($conditions as $key => &$condition) {
 | 
			
		||||
      if ($key !== '#conjunction' && is_string($condition['field']) && $condition['field'] === 'vocabulary_machine_name') {
 | 
			
		||||
        $condition['field'] = $vocabulary_alias . '.machine_name';
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Implements EntityReferenceHandler::getReferencableEntities().
 | 
			
		||||
   */
 | 
			
		||||
  public function getReferencableEntities($match = NULL, $match_operator = 'CONTAINS', $limit = 0) {
 | 
			
		||||
    if ($match || $limit) {
 | 
			
		||||
      return parent::getReferencableEntities($match , $match_operator, $limit);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $options = array();
 | 
			
		||||
    $entity_type = $this->field['settings']['target_type'];
 | 
			
		||||
 | 
			
		||||
    // We imitate core by calling taxonomy_get_tree().
 | 
			
		||||
    $entity_info = entity_get_info('taxonomy_term');
 | 
			
		||||
    $bundles = !empty($this->field['settings']['handler_settings']['target_bundles']) ? $this->field['settings']['handler_settings']['target_bundles'] : array_keys($entity_info['bundles']);
 | 
			
		||||
 | 
			
		||||
    foreach ($bundles as $bundle) {
 | 
			
		||||
      if ($vocabulary = taxonomy_vocabulary_machine_name_load($bundle)) {
 | 
			
		||||
        if ($terms = taxonomy_get_tree($vocabulary->vid, 0)) {
 | 
			
		||||
          foreach ($terms as $term) {
 | 
			
		||||
            $options[$vocabulary->machine_name][$term->tid] = str_repeat('-', $term->depth) . check_plain($term->name);
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return $options;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,553 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A generic Entity handler.
 | 
			
		||||
 *
 | 
			
		||||
 * The generic base implementation has a variety of overrides to workaround
 | 
			
		||||
 * core's largely deficient entity handling.
 | 
			
		||||
 */
 | 
			
		||||
class EntityReference_SelectionHandler_Generic implements EntityReference_SelectionHandler {
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Implements EntityReferenceHandler::getInstance().
 | 
			
		||||
   */
 | 
			
		||||
  public static function getInstance($field, $instance = NULL, $entity_type = NULL, $entity = NULL) {
 | 
			
		||||
    $target_entity_type = $field['settings']['target_type'];
 | 
			
		||||
 | 
			
		||||
    // Check if the entity type does exist and has a base table.
 | 
			
		||||
    $entity_info = entity_get_info($target_entity_type);
 | 
			
		||||
    if (empty($entity_info['base table'])) {
 | 
			
		||||
      return EntityReference_SelectionHandler_Broken::getInstance($field, $instance);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (class_exists($class_name = 'EntityReference_SelectionHandler_Generic_' . $target_entity_type)) {
 | 
			
		||||
      return new $class_name($field, $instance, $entity_type, $entity);
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
      return new EntityReference_SelectionHandler_Generic($field, $instance, $entity_type, $entity);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected function __construct($field, $instance = NULL, $entity_type = NULL, $entity = NULL) {
 | 
			
		||||
    $this->field = $field;
 | 
			
		||||
    $this->instance = $instance;
 | 
			
		||||
    $this->entity_type = $entity_type;
 | 
			
		||||
    $this->entity = $entity;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Implements EntityReferenceHandler::settingsForm().
 | 
			
		||||
   */
 | 
			
		||||
  public static function settingsForm($field, $instance) {
 | 
			
		||||
    $entity_info = entity_get_info($field['settings']['target_type']);
 | 
			
		||||
 | 
			
		||||
    // Merge-in default values.
 | 
			
		||||
    $field['settings']['handler_settings'] += array(
 | 
			
		||||
      'target_bundles' => array(),
 | 
			
		||||
      'sort' => array(
 | 
			
		||||
        'type' => 'none',
 | 
			
		||||
      )
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    if (!empty($entity_info['entity keys']['bundle'])) {
 | 
			
		||||
      $bundles = array();
 | 
			
		||||
      foreach ($entity_info['bundles'] as $bundle_name => $bundle_info) {
 | 
			
		||||
        $bundles[$bundle_name] = $bundle_info['label'];
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      $form['target_bundles'] = array(
 | 
			
		||||
        '#type' => 'checkboxes',
 | 
			
		||||
        '#title' => t('Target bundles'),
 | 
			
		||||
        '#options' => $bundles,
 | 
			
		||||
        '#default_value' => $field['settings']['handler_settings']['target_bundles'],
 | 
			
		||||
        '#size' => 6,
 | 
			
		||||
        '#multiple' => TRUE,
 | 
			
		||||
        '#description' => t('The bundles of the entity type that can be referenced. Optional, leave empty for all bundles.'),
 | 
			
		||||
        '#element_validate' => array('_entityreference_element_validate_filter'),
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
      $form['target_bundles'] = array(
 | 
			
		||||
        '#type' => 'value',
 | 
			
		||||
        '#value' => array(),
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $form['sort']['type'] = array(
 | 
			
		||||
      '#type' => 'select',
 | 
			
		||||
      '#title' => t('Sort by'),
 | 
			
		||||
      '#options' => array(
 | 
			
		||||
        'none' => t("Don't sort"),
 | 
			
		||||
        'property' => t('A property of the base table of the entity'),
 | 
			
		||||
        'field' => t('A field attached to this entity'),
 | 
			
		||||
      ),
 | 
			
		||||
      '#ajax' => TRUE,
 | 
			
		||||
      '#limit_validation_errors' => array(),
 | 
			
		||||
      '#default_value' => $field['settings']['handler_settings']['sort']['type'],
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    $form['sort']['settings'] = array(
 | 
			
		||||
      '#type' => 'container',
 | 
			
		||||
      '#attributes' => array('class' => array('entityreference-settings')),
 | 
			
		||||
      '#process' => array('_entityreference_form_process_merge_parent'),
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    if ($field['settings']['handler_settings']['sort']['type'] == 'property') {
 | 
			
		||||
      // Merge-in default values.
 | 
			
		||||
      $field['settings']['handler_settings']['sort'] += array(
 | 
			
		||||
        'property' => NULL,
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      $form['sort']['settings']['property'] = array(
 | 
			
		||||
        '#type' => 'select',
 | 
			
		||||
        '#title' => t('Sort property'),
 | 
			
		||||
        '#required' => TRUE,
 | 
			
		||||
        '#options' => drupal_map_assoc($entity_info['schema_fields_sql']['base table']),
 | 
			
		||||
        '#default_value' => $field['settings']['handler_settings']['sort']['property'],
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
    elseif ($field['settings']['handler_settings']['sort']['type'] == 'field') {
 | 
			
		||||
      // Merge-in default values.
 | 
			
		||||
      $field['settings']['handler_settings']['sort'] += array(
 | 
			
		||||
        'field' => NULL,
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      $fields = array();
 | 
			
		||||
      foreach (field_info_instances($field['settings']['target_type']) as $bundle_name => $bundle_instances) {
 | 
			
		||||
        foreach ($bundle_instances as $instance_name => $instance_info) {
 | 
			
		||||
          $field_info = field_info_field($instance_name);
 | 
			
		||||
          foreach ($field_info['columns'] as $column_name => $column_info) {
 | 
			
		||||
            $fields[$instance_name . ':' . $column_name] = t('@label (column @column)', array('@label' => $instance_info['label'], '@column' => $column_name));
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      $form['sort']['settings']['field'] = array(
 | 
			
		||||
        '#type' => 'select',
 | 
			
		||||
        '#title' => t('Sort field'),
 | 
			
		||||
        '#required' => TRUE,
 | 
			
		||||
        '#options' => $fields,
 | 
			
		||||
        '#default_value' => $field['settings']['handler_settings']['sort']['field'],
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ($field['settings']['handler_settings']['sort']['type'] != 'none') {
 | 
			
		||||
      // Merge-in default values.
 | 
			
		||||
      $field['settings']['handler_settings']['sort'] += array(
 | 
			
		||||
        'direction' => 'ASC',
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      $form['sort']['settings']['direction'] = array(
 | 
			
		||||
        '#type' => 'select',
 | 
			
		||||
        '#title' => t('Sort direction'),
 | 
			
		||||
        '#required' => TRUE,
 | 
			
		||||
        '#options' => array(
 | 
			
		||||
          'ASC' => t('Ascending'),
 | 
			
		||||
          'DESC' => t('Descending'),
 | 
			
		||||
        ),
 | 
			
		||||
        '#default_value' => $field['settings']['handler_settings']['sort']['direction'],
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return $form;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Implements EntityReferenceHandler::getReferencableEntities().
 | 
			
		||||
   */
 | 
			
		||||
  public function getReferencableEntities($match = NULL, $match_operator = 'CONTAINS', $limit = 0) {
 | 
			
		||||
    $options = array();
 | 
			
		||||
    $entity_type = $this->field['settings']['target_type'];
 | 
			
		||||
 | 
			
		||||
    $query = $this->buildEntityFieldQuery($match, $match_operator);
 | 
			
		||||
    if ($limit > 0) {
 | 
			
		||||
      $query->range(0, $limit);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $results = $query->execute();
 | 
			
		||||
 | 
			
		||||
    if (!empty($results[$entity_type])) {
 | 
			
		||||
      $entities = entity_load($entity_type, array_keys($results[$entity_type]));
 | 
			
		||||
      foreach ($entities as $entity_id => $entity) {
 | 
			
		||||
        list(,, $bundle) = entity_extract_ids($entity_type, $entity);
 | 
			
		||||
        $options[$bundle][$entity_id] = check_plain($this->getLabel($entity));
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return $options;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Implements EntityReferenceHandler::countReferencableEntities().
 | 
			
		||||
   */
 | 
			
		||||
  public function countReferencableEntities($match = NULL, $match_operator = 'CONTAINS') {
 | 
			
		||||
    $query = $this->buildEntityFieldQuery($match, $match_operator);
 | 
			
		||||
    return $query
 | 
			
		||||
      ->count()
 | 
			
		||||
      ->execute();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Implements EntityReferenceHandler::validateReferencableEntities().
 | 
			
		||||
   */
 | 
			
		||||
  public function validateReferencableEntities(array $ids) {
 | 
			
		||||
    if ($ids) {
 | 
			
		||||
      $entity_type = $this->field['settings']['target_type'];
 | 
			
		||||
      $query = $this->buildEntityFieldQuery();
 | 
			
		||||
      $query->entityCondition('entity_id', $ids, 'IN');
 | 
			
		||||
      $result = $query->execute();
 | 
			
		||||
      if (!empty($result[$entity_type])) {
 | 
			
		||||
        return array_keys($result[$entity_type]);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return array();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Implements EntityReferenceHandler::validateAutocompleteInput().
 | 
			
		||||
   */
 | 
			
		||||
  public function validateAutocompleteInput($input, &$element, &$form_state, $form) {
 | 
			
		||||
      $entities = $this->getReferencableEntities($input, '=', 6);
 | 
			
		||||
      if (empty($entities)) {
 | 
			
		||||
        // Error if there are no entities available for a required field.
 | 
			
		||||
        form_error($element, t('There are no entities matching "%value"', array('%value' => $input)));
 | 
			
		||||
      }
 | 
			
		||||
      elseif (count($entities) > 5) {
 | 
			
		||||
        // Error if there are more than 5 matching entities.
 | 
			
		||||
        form_error($element, t('Many entities are called %value. Specify the one you want by appending the id in parentheses, like "@value (@id)"', array(
 | 
			
		||||
          '%value' => $input,
 | 
			
		||||
          '@value' => $input,
 | 
			
		||||
          '@id' => key($entities),
 | 
			
		||||
        )));
 | 
			
		||||
      }
 | 
			
		||||
      elseif (count($entities) > 1) {
 | 
			
		||||
        // More helpful error if there are only a few matching entities.
 | 
			
		||||
        $multiples = array();
 | 
			
		||||
        foreach ($entities as $id => $name) {
 | 
			
		||||
          $multiples[] = $name . ' (' . $id . ')';
 | 
			
		||||
        }
 | 
			
		||||
        form_error($element, t('Multiple entities match this reference; "%multiple"', array('%multiple' => implode('", "', $multiples))));
 | 
			
		||||
      }
 | 
			
		||||
      else {
 | 
			
		||||
        // Take the one and only matching entity.
 | 
			
		||||
        return key($entities);
 | 
			
		||||
      }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Build an EntityFieldQuery to get referencable entities.
 | 
			
		||||
   */
 | 
			
		||||
  protected function buildEntityFieldQuery($match = NULL, $match_operator = 'CONTAINS') {
 | 
			
		||||
    $query = new EntityFieldQuery();
 | 
			
		||||
    $query->entityCondition('entity_type', $this->field['settings']['target_type']);
 | 
			
		||||
    if (!empty($this->field['settings']['handler_settings']['target_bundles'])) {
 | 
			
		||||
      $query->entityCondition('bundle', $this->field['settings']['handler_settings']['target_bundles'], 'IN');
 | 
			
		||||
    }
 | 
			
		||||
    if (isset($match)) {
 | 
			
		||||
      $entity_info = entity_get_info($this->field['settings']['target_type']);
 | 
			
		||||
      if (isset($entity_info['entity keys']['label'])) {
 | 
			
		||||
        $query->propertyCondition($entity_info['entity keys']['label'], $match, $match_operator);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Add a generic entity access tag to the query.
 | 
			
		||||
    $query->addTag($this->field['settings']['target_type'] . '_access');
 | 
			
		||||
    $query->addTag('entityreference');
 | 
			
		||||
    $query->addMetaData('field', $this->field);
 | 
			
		||||
    $query->addMetaData('entityreference_selection_handler', $this);
 | 
			
		||||
 | 
			
		||||
    // Add the sort option.
 | 
			
		||||
    if (!empty($this->field['settings']['handler_settings']['sort'])) {
 | 
			
		||||
      $sort_settings = $this->field['settings']['handler_settings']['sort'];
 | 
			
		||||
      if ($sort_settings['type'] == 'property') {
 | 
			
		||||
        $query->propertyOrderBy($sort_settings['property'], $sort_settings['direction']);
 | 
			
		||||
      }
 | 
			
		||||
      elseif ($sort_settings['type'] == 'field') {
 | 
			
		||||
        list($field, $column) = explode(':', $sort_settings['field'], 2);
 | 
			
		||||
        $query->fieldOrderBy($field, $column, $sort_settings['direction']);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return $query;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Implements EntityReferenceHandler::entityFieldQueryAlter().
 | 
			
		||||
   */
 | 
			
		||||
  public function entityFieldQueryAlter(SelectQueryInterface $query) {
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Helper method: pass a query to the alteration system again.
 | 
			
		||||
   *
 | 
			
		||||
   * This allow Entity Reference to add a tag to an existing query, to ask
 | 
			
		||||
   * access control mechanisms to alter it again.
 | 
			
		||||
   */
 | 
			
		||||
  protected function reAlterQuery(SelectQueryInterface $query, $tag, $base_table) {
 | 
			
		||||
    // Save the old tags and metadata.
 | 
			
		||||
    // For some reason, those are public.
 | 
			
		||||
    $old_tags = $query->alterTags;
 | 
			
		||||
    $old_metadata = $query->alterMetaData;
 | 
			
		||||
 | 
			
		||||
    $query->alterTags = array($tag => TRUE);
 | 
			
		||||
    $query->alterMetaData['base_table'] = $base_table;
 | 
			
		||||
    drupal_alter(array('query', 'query_' . $tag), $query);
 | 
			
		||||
 | 
			
		||||
    // Restore the tags and metadata.
 | 
			
		||||
    $query->alterTags = $old_tags;
 | 
			
		||||
    $query->alterMetaData = $old_metadata;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Implements EntityReferenceHandler::getLabel().
 | 
			
		||||
   */
 | 
			
		||||
  public function getLabel($entity) {
 | 
			
		||||
    return entity_label($this->field['settings']['target_type'], $entity);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Ensure a base table exists for the query.
 | 
			
		||||
   *
 | 
			
		||||
   * If we have a field-only query, we want to assure we have a base-table
 | 
			
		||||
   * so we can later alter the query in entityFieldQueryAlter().
 | 
			
		||||
   *
 | 
			
		||||
   * @param $query
 | 
			
		||||
   *   The Select query.
 | 
			
		||||
   *
 | 
			
		||||
   * @return
 | 
			
		||||
   *   The alias of the base-table.
 | 
			
		||||
   */
 | 
			
		||||
  public function ensureBaseTable(SelectQueryInterface $query) {
 | 
			
		||||
    $tables = $query->getTables();
 | 
			
		||||
 | 
			
		||||
    // Check the current base table.
 | 
			
		||||
    foreach ($tables as $table) {
 | 
			
		||||
      if (empty($table['join'])) {
 | 
			
		||||
        $alias = $table['alias'];
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (strpos($alias, 'field_data_') !== 0) {
 | 
			
		||||
      // The existing base-table is the correct one.
 | 
			
		||||
      return $alias;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Join the known base-table.
 | 
			
		||||
    $target_type = $this->field['settings']['target_type'];
 | 
			
		||||
    $entity_info = entity_get_info($target_type);
 | 
			
		||||
    $id = $entity_info['entity keys']['id'];
 | 
			
		||||
    // Return the alias of the table.
 | 
			
		||||
    return $query->innerJoin($target_type, NULL, "$target_type.$id = $alias.entity_id");
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Override for the Node type.
 | 
			
		||||
 *
 | 
			
		||||
 * This only exists to workaround core bugs.
 | 
			
		||||
 */
 | 
			
		||||
class EntityReference_SelectionHandler_Generic_node extends EntityReference_SelectionHandler_Generic {
 | 
			
		||||
  public function entityFieldQueryAlter(SelectQueryInterface $query) {
 | 
			
		||||
    // Adding the 'node_access' tag is sadly insufficient for nodes: core
 | 
			
		||||
    // requires us to also know about the concept of 'published' and
 | 
			
		||||
    // 'unpublished'. We need to do that as long as there are no access control
 | 
			
		||||
    // modules in use on the site. As long as one access control module is there,
 | 
			
		||||
    // it is supposed to handle this check.
 | 
			
		||||
    if (!user_access('bypass node access') && !count(module_implements('node_grants'))) {
 | 
			
		||||
      $base_table = $this->ensureBaseTable($query);
 | 
			
		||||
      $query->condition("$base_table.status", NODE_PUBLISHED);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Override for the User type.
 | 
			
		||||
 *
 | 
			
		||||
 * This only exists to workaround core bugs.
 | 
			
		||||
 */
 | 
			
		||||
class EntityReference_SelectionHandler_Generic_user extends EntityReference_SelectionHandler_Generic {
 | 
			
		||||
  public function buildEntityFieldQuery($match = NULL, $match_operator = 'CONTAINS') {
 | 
			
		||||
    $query = parent::buildEntityFieldQuery($match, $match_operator);
 | 
			
		||||
 | 
			
		||||
    // The user entity doesn't have a label column.
 | 
			
		||||
    if (isset($match)) {
 | 
			
		||||
      $query->propertyCondition('name', $match, $match_operator);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Adding the 'user_access' tag is sadly insufficient for users: core
 | 
			
		||||
    // requires us to also know about the concept of 'blocked' and
 | 
			
		||||
    // 'active'.
 | 
			
		||||
    if (!user_access('administer users')) {
 | 
			
		||||
      $query->propertyCondition('status', 1);
 | 
			
		||||
    }
 | 
			
		||||
    return $query;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function entityFieldQueryAlter(SelectQueryInterface $query) {
 | 
			
		||||
    if (user_access('administer users')) {
 | 
			
		||||
      // In addition, if the user is administrator, we need to make sure to
 | 
			
		||||
      // match the anonymous user, that doesn't actually have a name in the
 | 
			
		||||
      // database.
 | 
			
		||||
      $conditions = &$query->conditions();
 | 
			
		||||
      foreach ($conditions as $key => $condition) {
 | 
			
		||||
        if ($key !== '#conjunction' && is_string($condition['field']) && $condition['field'] === 'users.name') {
 | 
			
		||||
          // Remove the condition.
 | 
			
		||||
          unset($conditions[$key]);
 | 
			
		||||
 | 
			
		||||
          // Re-add the condition and a condition on uid = 0 so that we end up
 | 
			
		||||
          // with a query in the form:
 | 
			
		||||
          //    WHERE (name LIKE :name) OR (:anonymous_name LIKE :name AND uid = 0)
 | 
			
		||||
          $or = db_or();
 | 
			
		||||
          $or->condition($condition['field'], $condition['value'], $condition['operator']);
 | 
			
		||||
          // Sadly, the Database layer doesn't allow us to build a condition
 | 
			
		||||
          // in the form ':placeholder = :placeholder2', because the 'field'
 | 
			
		||||
          // part of a condition is always escaped.
 | 
			
		||||
          // As a (cheap) workaround, we separately build a condition with no
 | 
			
		||||
          // field, and concatenate the field and the condition separately.
 | 
			
		||||
          $value_part = db_and();
 | 
			
		||||
          $value_part->condition('anonymous_name', $condition['value'], $condition['operator']);
 | 
			
		||||
          $value_part->compile(Database::getConnection(), $query);
 | 
			
		||||
          $or->condition(db_and()
 | 
			
		||||
            ->where(str_replace('anonymous_name', ':anonymous_name', (string) $value_part), $value_part->arguments() + array(':anonymous_name' => format_username(user_load(0))))
 | 
			
		||||
            ->condition('users.uid', 0)
 | 
			
		||||
          );
 | 
			
		||||
          $query->condition($or);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Override for the Comment type.
 | 
			
		||||
 *
 | 
			
		||||
 * This only exists to workaround core bugs.
 | 
			
		||||
 */
 | 
			
		||||
class EntityReference_SelectionHandler_Generic_comment extends EntityReference_SelectionHandler_Generic {
 | 
			
		||||
  public function entityFieldQueryAlter(SelectQueryInterface $query) {
 | 
			
		||||
    // Adding the 'comment_access' tag is sadly insufficient for comments: core
 | 
			
		||||
    // requires us to also know about the concept of 'published' and
 | 
			
		||||
    // 'unpublished'.
 | 
			
		||||
    if (!user_access('administer comments')) {
 | 
			
		||||
      $base_table = $this->ensureBaseTable($query);
 | 
			
		||||
      $query->condition("$base_table.status", COMMENT_PUBLISHED);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // The Comment module doesn't implement any proper comment access,
 | 
			
		||||
    // and as a consequence doesn't make sure that comments cannot be viewed
 | 
			
		||||
    // when the user doesn't have access to the node.
 | 
			
		||||
    $tables = $query->getTables();
 | 
			
		||||
    $base_table = key($tables);
 | 
			
		||||
    $node_alias = $query->innerJoin('node', 'n', '%alias.nid = ' . $base_table . '.nid');
 | 
			
		||||
    // Pass the query to the node access control.
 | 
			
		||||
    $this->reAlterQuery($query, 'node_access', $node_alias);
 | 
			
		||||
 | 
			
		||||
    // Alas, the comment entity exposes a bundle, but doesn't have a bundle column
 | 
			
		||||
    // in the database. We have to alter the query ourself to go fetch the
 | 
			
		||||
    // bundle.
 | 
			
		||||
    $conditions = &$query->conditions();
 | 
			
		||||
    foreach ($conditions as $key => &$condition) {
 | 
			
		||||
      if ($key !== '#conjunction' && is_string($condition['field']) && $condition['field'] === 'node_type') {
 | 
			
		||||
        $condition['field'] = $node_alias . '.type';
 | 
			
		||||
        foreach ($condition['value'] as &$value) {
 | 
			
		||||
          if (substr($value, 0, 13) == 'comment_node_') {
 | 
			
		||||
            $value = substr($value, 13);
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Passing the query to node_query_node_access_alter() is sadly
 | 
			
		||||
    // insufficient for nodes.
 | 
			
		||||
    // @see EntityReferenceHandler_node::entityFieldQueryAlter()
 | 
			
		||||
    if (!user_access('bypass node access') && !count(module_implements('node_grants'))) {
 | 
			
		||||
      $query->condition($node_alias . '.status', 1);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Override for the File type.
 | 
			
		||||
 *
 | 
			
		||||
 * This only exists to workaround core bugs.
 | 
			
		||||
 */
 | 
			
		||||
class EntityReference_SelectionHandler_Generic_file extends EntityReference_SelectionHandler_Generic {
 | 
			
		||||
  public function entityFieldQueryAlter(SelectQueryInterface $query) {
 | 
			
		||||
    // Core forces us to know about 'permanent' vs. 'temporary' files.
 | 
			
		||||
    $tables = $query->getTables();
 | 
			
		||||
    $base_table = key($tables);
 | 
			
		||||
    $query->condition('status', FILE_STATUS_PERMANENT);
 | 
			
		||||
 | 
			
		||||
    // Access control to files is a very difficult business. For now, we are not
 | 
			
		||||
    // going to give it a shot.
 | 
			
		||||
    // @todo: fix this when core access control is less insane.
 | 
			
		||||
    return $query;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function getLabel($entity) {
 | 
			
		||||
    // The file entity doesn't have a label. More over, the filename is
 | 
			
		||||
    // sometimes empty, so use the basename in that case.
 | 
			
		||||
    return $entity->filename !== '' ? $entity->filename : basename($entity->uri);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Override for the Taxonomy term type.
 | 
			
		||||
 *
 | 
			
		||||
 * This only exists to workaround core bugs.
 | 
			
		||||
 */
 | 
			
		||||
class EntityReference_SelectionHandler_Generic_taxonomy_term extends EntityReference_SelectionHandler_Generic {
 | 
			
		||||
  public function entityFieldQueryAlter(SelectQueryInterface $query) {
 | 
			
		||||
    // The Taxonomy module doesn't implement any proper taxonomy term access,
 | 
			
		||||
    // and as a consequence doesn't make sure that taxonomy terms cannot be viewed
 | 
			
		||||
    // when the user doesn't have access to the vocabulary.
 | 
			
		||||
    $base_table = $this->ensureBaseTable($query);
 | 
			
		||||
    $vocabulary_alias = $query->innerJoin('taxonomy_vocabulary', 'n', '%alias.vid = ' . $base_table . '.vid');
 | 
			
		||||
    $query->addMetadata('base_table', $vocabulary_alias);
 | 
			
		||||
    // Pass the query to the taxonomy access control.
 | 
			
		||||
    $this->reAlterQuery($query, 'taxonomy_vocabulary_access', $vocabulary_alias);
 | 
			
		||||
 | 
			
		||||
    // Also, the taxonomy term entity exposes a bundle, but doesn't have a bundle
 | 
			
		||||
    // column in the database. We have to alter the query ourself to go fetch
 | 
			
		||||
    // the bundle.
 | 
			
		||||
    $conditions = &$query->conditions();
 | 
			
		||||
    foreach ($conditions as $key => &$condition) {
 | 
			
		||||
      if ($key !== '#conjunction' && is_string($condition['field']) && $condition['field'] === 'vocabulary_machine_name') {
 | 
			
		||||
        $condition['field'] = $vocabulary_alias . '.machine_name';
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Implements EntityReferenceHandler::getReferencableEntities().
 | 
			
		||||
   */
 | 
			
		||||
  public function getReferencableEntities($match = NULL, $match_operator = 'CONTAINS', $limit = 0) {
 | 
			
		||||
    if ($match || $limit) {
 | 
			
		||||
      return parent::getReferencableEntities($match , $match_operator, $limit);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $options = array();
 | 
			
		||||
    $entity_type = $this->field['settings']['target_type'];
 | 
			
		||||
 | 
			
		||||
    // We imitate core by calling taxonomy_get_tree().
 | 
			
		||||
    $entity_info = entity_get_info('taxonomy_term');
 | 
			
		||||
    $bundles = !empty($this->field['settings']['handler_settings']['target_bundles']) ? $this->field['settings']['handler_settings']['target_bundles'] : array_keys($entity_info['bundles']);
 | 
			
		||||
 | 
			
		||||
    foreach ($bundles as $bundle) {
 | 
			
		||||
      if ($vocabulary = taxonomy_vocabulary_machine_name_load($bundle)) {
 | 
			
		||||
        if ($terms = taxonomy_get_tree($vocabulary->vid, 0)) {
 | 
			
		||||
          foreach ($terms as $term) {
 | 
			
		||||
            $options[$vocabulary->machine_name][$term->tid] = str_repeat('-', $term->depth) . check_plain($term->name);
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return $options;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,193 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Entity handler for Views.
 | 
			
		||||
 */
 | 
			
		||||
class EntityReference_SelectionHandler_Views implements EntityReference_SelectionHandler {
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Implements EntityReferenceHandler::getInstance().
 | 
			
		||||
   */
 | 
			
		||||
  public static function getInstance($field, $instance = NULL, $entity_type = NULL, $entity = NULL) {
 | 
			
		||||
    return new EntityReference_SelectionHandler_Views($field, $instance);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected function __construct($field, $instance) {
 | 
			
		||||
    $this->field = $field;
 | 
			
		||||
    $this->instance = $instance;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Implements EntityReferenceHandler::settingsForm().
 | 
			
		||||
   */
 | 
			
		||||
  public static function settingsForm($field, $instance) {
 | 
			
		||||
    $view_settings = empty($field['settings']['handler_settings']['view']) ? '' : $field['settings']['handler_settings']['view'];
 | 
			
		||||
    $displays = views_get_applicable_views('entityreference display');
 | 
			
		||||
    // Filter views that list the entity type we want, and group the separate
 | 
			
		||||
    // displays by view.
 | 
			
		||||
    $entity_info = entity_get_info($field['settings']['target_type']);
 | 
			
		||||
    $options = array();
 | 
			
		||||
    foreach ($displays as $data) {
 | 
			
		||||
      list($view, $display_id) = $data;
 | 
			
		||||
      if ($view->base_table == $entity_info['base table']) {
 | 
			
		||||
        $options[$view->name . ':' . $display_id] = $view->name . ' - ' . $view->display[$display_id]->display_title;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // The value of the 'view_and_display' select below will need to be split
 | 
			
		||||
    // into 'view_name' and 'view_display' in the final submitted values, so
 | 
			
		||||
    // we massage the data at validate time on the wrapping element (not
 | 
			
		||||
    // ideal).
 | 
			
		||||
    $form['view']['#element_validate'] = array('entityreference_view_settings_validate');
 | 
			
		||||
 | 
			
		||||
    if ($options) {
 | 
			
		||||
      $default = !empty($view_settings['view_name']) ? $view_settings['view_name'] . ':' . $view_settings['display_name'] : NULL;
 | 
			
		||||
      $form['view']['view_and_display'] = array(
 | 
			
		||||
        '#type' => 'select',
 | 
			
		||||
        '#title' => t('View used to select the entities'),
 | 
			
		||||
        '#required' => TRUE,
 | 
			
		||||
        '#options' => $options,
 | 
			
		||||
        '#default_value' => $default,
 | 
			
		||||
        '#description' => '<p>' . t('Choose the view and display that select the entities that can be referenced.<br />Only views with a display of type "Entity Reference" are eligible.') . '</p>',
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      $default = !empty($view_settings['args']) ? implode(', ', $view_settings['args']) : '';
 | 
			
		||||
      $form['view']['args'] = array(
 | 
			
		||||
        '#type' => 'textfield',
 | 
			
		||||
        '#title' => t('View arguments'),
 | 
			
		||||
        '#default_value' => $default,
 | 
			
		||||
        '#required' => FALSE,
 | 
			
		||||
        '#description' => t('Provide a comma separated list of arguments to pass to the view.'),
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
      $form['view']['no_view_help'] = array(
 | 
			
		||||
        '#markup' => '<p>' . t('No eligible views were found. <a href="@create">Create a view</a> with an <em>Entity Reference</em> display, or add such a display to an <a href="@existing">existing view</a>.', array(
 | 
			
		||||
          '@create' => url('admin/structure/views/add'),
 | 
			
		||||
          '@existing' => url('admin/structure/views'),
 | 
			
		||||
        )) . '</p>',
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
    return $form;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected function initializeView($match = NULL, $match_operator = 'CONTAINS', $limit = 0, $ids = NULL) {
 | 
			
		||||
    $view_name = $this->field['settings']['handler_settings']['view']['view_name'];
 | 
			
		||||
    $display_name = $this->field['settings']['handler_settings']['view']['display_name'];
 | 
			
		||||
    $args = $this->field['settings']['handler_settings']['view']['args'];
 | 
			
		||||
    $entity_type = $this->field['settings']['target_type'];
 | 
			
		||||
 | 
			
		||||
    // Check that the view is valid and the display still exists.
 | 
			
		||||
    $this->view = views_get_view($view_name);
 | 
			
		||||
    if (!$this->view || !isset($this->view->display[$display_name]) || !$this->view->access($display_name)) {
 | 
			
		||||
      watchdog('entityreference', 'The view %view_name is no longer eligible for the %field_name field.', array('%view_name' => $view_name, '%field_name' => $this->instance['label']), WATCHDOG_WARNING);
 | 
			
		||||
      return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
    $this->view->set_display($display_name);
 | 
			
		||||
 | 
			
		||||
    // Make sure the query is not cached.
 | 
			
		||||
    $this->view->is_cacheable = FALSE;
 | 
			
		||||
 | 
			
		||||
    // Pass options to the display handler to make them available later.
 | 
			
		||||
    $entityreference_options = array(
 | 
			
		||||
      'match' => $match,
 | 
			
		||||
      'match_operator' => $match_operator,
 | 
			
		||||
      'limit' => $limit,
 | 
			
		||||
      'ids' => $ids,
 | 
			
		||||
    );
 | 
			
		||||
    $this->view->display_handler->set_option('entityreference_options', $entityreference_options);
 | 
			
		||||
    return TRUE;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Implements EntityReferenceHandler::getReferencableEntities().
 | 
			
		||||
   */
 | 
			
		||||
  public function getReferencableEntities($match = NULL, $match_operator = 'CONTAINS', $limit = 0) {
 | 
			
		||||
    $display_name = $this->field['settings']['handler_settings']['view']['display_name'];
 | 
			
		||||
    $args = $this->field['settings']['handler_settings']['view']['args'];
 | 
			
		||||
    $result = array();
 | 
			
		||||
    if ($this->initializeView($match, $match_operator, $limit)) {
 | 
			
		||||
      // Get the results.
 | 
			
		||||
      $result = $this->view->execute_display($display_name, $args);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $return = array();
 | 
			
		||||
    if ($result) {
 | 
			
		||||
      $target_type = $this->field['settings']['target_type'];
 | 
			
		||||
      $entities = entity_load($target_type, array_keys($result));
 | 
			
		||||
      foreach($entities as $entity) {
 | 
			
		||||
        list($id,, $bundle) = entity_extract_ids($target_type, $entity);
 | 
			
		||||
        $return[$bundle][$id] = $result[$id];
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return $return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Implements EntityReferenceHandler::countReferencableEntities().
 | 
			
		||||
   */
 | 
			
		||||
  function countReferencableEntities($match = NULL, $match_operator = 'CONTAINS') {
 | 
			
		||||
    $this->getReferencableEntities($match, $match_operator);
 | 
			
		||||
    return $this->view->total_items;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function validateReferencableEntities(array $ids) {
 | 
			
		||||
    $display_name = $this->field['settings']['handler_settings']['view']['display_name'];
 | 
			
		||||
    $args = $this->field['settings']['handler_settings']['view']['args'];
 | 
			
		||||
    $result = array();
 | 
			
		||||
    if ($this->initializeView(NULL, 'CONTAINS', 0, $ids)) {
 | 
			
		||||
      // Get the results.
 | 
			
		||||
      $entities = $this->view->execute_display($display_name, $args);
 | 
			
		||||
      $result = array_keys($entities);
 | 
			
		||||
    }
 | 
			
		||||
    return $result;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Implements EntityReferenceHandler::validateAutocompleteInput().
 | 
			
		||||
   */
 | 
			
		||||
  public function validateAutocompleteInput($input, &$element, &$form_state, $form) {
 | 
			
		||||
    return NULL;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Implements EntityReferenceHandler::getLabel().
 | 
			
		||||
   */
 | 
			
		||||
  public function getLabel($entity) {
 | 
			
		||||
    return entity_label($this->field['settings']['target_type'], $entity);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Implements EntityReferenceHandler::entityFieldQueryAlter().
 | 
			
		||||
   */
 | 
			
		||||
  public function entityFieldQueryAlter(SelectQueryInterface $query) {
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function entityreference_view_settings_validate($element, &$form_state, $form) {
 | 
			
		||||
  // Split view name and display name from the 'view_and_display' value.
 | 
			
		||||
  if (!empty($element['view_and_display']['#value'])) {
 | 
			
		||||
    list($view, $display) = explode(':', $element['view_and_display']['#value']);
 | 
			
		||||
  }
 | 
			
		||||
  else {
 | 
			
		||||
    form_error($element, t('The views entity selection mode requires a view.'));
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Explode the 'args' string into an actual array. Beware, explode() turns an
 | 
			
		||||
  // empty string into an array with one empty string. We'll need an empty array
 | 
			
		||||
  // instead.
 | 
			
		||||
  $args_string = trim($element['args']['#value']);
 | 
			
		||||
  if ($args_string === '') {
 | 
			
		||||
    $args = array();
 | 
			
		||||
  }
 | 
			
		||||
  else {
 | 
			
		||||
    // array_map is called to trim whitespaces from the arguments.
 | 
			
		||||
    $args = array_map('trim', explode(',', $args_string));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  $value = array('view_name' => $view, 'display_name' => $display, 'args' => $args);
 | 
			
		||||
  form_set_value($element, $value, $form_state);
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,113 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @file
 | 
			
		||||
 * Abstraction of the selection logic of an entity reference field.
 | 
			
		||||
 *
 | 
			
		||||
 * Implementations that wish to provide an implementation of this should
 | 
			
		||||
 * register it using CTools' plugin system.
 | 
			
		||||
 */
 | 
			
		||||
interface EntityReference_SelectionHandler {
 | 
			
		||||
  /**
 | 
			
		||||
   * Factory function: create a new instance of this handler for a given field.
 | 
			
		||||
   *
 | 
			
		||||
   * @param $field
 | 
			
		||||
   *   A field datastructure.
 | 
			
		||||
   * @return EntityReferenceHandler
 | 
			
		||||
   */
 | 
			
		||||
  public static function getInstance($field, $instance = NULL, $entity_type = NULL, $entity = NULL);
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Return a list of referencable entities.
 | 
			
		||||
   *
 | 
			
		||||
   * @return
 | 
			
		||||
   *   An array of referencable entities, which keys are entity ids and
 | 
			
		||||
   *   values (safe HTML) labels to be displayed to the user.
 | 
			
		||||
   */
 | 
			
		||||
  public function getReferencableEntities($match = NULL, $match_operator = 'CONTAINS', $limit = 0);
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Count entities that are referencable by a given field.
 | 
			
		||||
   */
 | 
			
		||||
  public function countReferencableEntities($match = NULL, $match_operator = 'CONTAINS');
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Validate that entities can be referenced by this field.
 | 
			
		||||
   *
 | 
			
		||||
   * @return
 | 
			
		||||
   *   An array of entity ids that are valid.
 | 
			
		||||
   */
 | 
			
		||||
  public function validateReferencableEntities(array $ids);
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Validate Input from autocomplete widget that has no Id.
 | 
			
		||||
   *
 | 
			
		||||
   * @see _entityreference_autocomplete_validate()
 | 
			
		||||
   *
 | 
			
		||||
   * @param $input
 | 
			
		||||
   * 	 Single string from autocomplete widget.
 | 
			
		||||
   * @param $element
 | 
			
		||||
   *   The form element to set a form error.
 | 
			
		||||
   * @return
 | 
			
		||||
   *   Value of a matching entity id, or NULL if none.
 | 
			
		||||
   */
 | 
			
		||||
  public function validateAutocompleteInput($input, &$element, &$form_state, $form);
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Give the handler a chance to alter the SelectQuery generated by EntityFieldQuery.
 | 
			
		||||
   */
 | 
			
		||||
  public function entityFieldQueryAlter(SelectQueryInterface $query);
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Return the label of a given entity.
 | 
			
		||||
   */
 | 
			
		||||
  public function getLabel($entity);
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Generate a settings form for this handler.
 | 
			
		||||
   */
 | 
			
		||||
  public static function settingsForm($field, $instance);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A null implementation of EntityReference_SelectionHandler.
 | 
			
		||||
 */
 | 
			
		||||
class EntityReference_SelectionHandler_Broken implements EntityReference_SelectionHandler {
 | 
			
		||||
  public static function getInstance($field, $instance = NULL, $entity_type = NULL, $entity = NULL) {
 | 
			
		||||
    return new EntityReference_SelectionHandler_Broken($field, $instance, $entity_type, $entity);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected function __construct($field, $instance) {
 | 
			
		||||
    $this->field = $field;
 | 
			
		||||
    $this->instance = $instance;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public static function settingsForm($field, $instance) {
 | 
			
		||||
    $form['selection_handler'] = array(
 | 
			
		||||
      '#markup' => t('The selected selection handler is broken.'),
 | 
			
		||||
    );
 | 
			
		||||
    return $form;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function getReferencableEntities($match = NULL, $match_operator = 'CONTAINS', $limit = 0) {
 | 
			
		||||
    return array();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function countReferencableEntities($match = NULL, $match_operator = 'CONTAINS') {
 | 
			
		||||
    return 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function validateReferencableEntities(array $ids) {
 | 
			
		||||
    return array();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function validateAutocompleteInput($input, &$element, &$form_state, $form) {
 | 
			
		||||
    return NULL;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function entityFieldQueryAlter(SelectQueryInterface $query) {}
 | 
			
		||||
 | 
			
		||||
  public function getLabel($entity) {
 | 
			
		||||
    return '';
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,7 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
$plugin = array(
 | 
			
		||||
  'title' => t('Simple (with optional filter by bundle)'),
 | 
			
		||||
  'class' => 'EntityReference_SelectionHandler_Generic',
 | 
			
		||||
  'weight' => -100,
 | 
			
		||||
);
 | 
			
		||||
@@ -0,0 +1,9 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
if (module_exists('views')) {
 | 
			
		||||
  $plugin = array(
 | 
			
		||||
    'title' => t('Views: Filter by an entity reference view'),
 | 
			
		||||
    'class' => 'EntityReference_SelectionHandler_Views',
 | 
			
		||||
    'weight' => 0,
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,114 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @file
 | 
			
		||||
 * Contains EntityReferenceHandlersTestCase
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Test for Entity Reference admin UI.
 | 
			
		||||
 */
 | 
			
		||||
class EntityReferenceAdminTestCase extends DrupalWebTestCase {
 | 
			
		||||
  public static function getInfo() {
 | 
			
		||||
    return array(
 | 
			
		||||
      'name' => 'Entity Reference UI',
 | 
			
		||||
      'description' => 'Tests for the administrative UI.',
 | 
			
		||||
      'group' => 'Entity Reference',
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function setUp() {
 | 
			
		||||
    parent::setUp(array('field_ui', 'entity', 'ctools', 'entityreference'));
 | 
			
		||||
 | 
			
		||||
    // Create test user.
 | 
			
		||||
    $this->admin_user = $this->drupalCreateUser(array('access content', 'administer content types'));
 | 
			
		||||
    $this->drupalLogin($this->admin_user);
 | 
			
		||||
 | 
			
		||||
    // Create content type, with underscores.
 | 
			
		||||
    $type_name = strtolower($this->randomName(8)) . '_test';
 | 
			
		||||
    $type = $this->drupalCreateContentType(array('name' => $type_name, 'type' => $type_name));
 | 
			
		||||
    $this->type = $type->type;
 | 
			
		||||
    // Store a valid URL name, with hyphens instead of underscores.
 | 
			
		||||
    $this->hyphen_type = str_replace('_', '-', $this->type);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected function assertFieldSelectOptions($name, $expected_options) {
 | 
			
		||||
    $xpath = $this->buildXPathQuery('//select[@name=:name]', array(':name' => $name));
 | 
			
		||||
    $fields = $this->xpath($xpath);
 | 
			
		||||
    if ($fields) {
 | 
			
		||||
      $field = $fields[0];
 | 
			
		||||
      $options = $this->getAllOptionsList($field);
 | 
			
		||||
      return $this->assertIdentical($options, $expected_options);
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
      return $this->fail(t('Unable to find field @name', array('@name' => $name)));
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Extract all the options of a select element.
 | 
			
		||||
   */
 | 
			
		||||
  protected function getAllOptionsList($element) {
 | 
			
		||||
    $options = array();
 | 
			
		||||
    // Add all options items.
 | 
			
		||||
    foreach ($element->option as $option) {
 | 
			
		||||
      $options[] = (string) $option['value'];
 | 
			
		||||
    }
 | 
			
		||||
    // TODO: support optgroup.
 | 
			
		||||
    return $options;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function testFieldAdminHandler() {
 | 
			
		||||
    $bundle_path = 'admin/structure/types/manage/' . $this->hyphen_type;
 | 
			
		||||
 | 
			
		||||
    // First step: 'Add new field' on the 'Manage fields' page.
 | 
			
		||||
    $this->drupalPost($bundle_path . '/fields', array(
 | 
			
		||||
      'fields[_add_new_field][label]' => 'Test label',
 | 
			
		||||
      'fields[_add_new_field][field_name]' => 'test',
 | 
			
		||||
      'fields[_add_new_field][type]' => 'entityreference',
 | 
			
		||||
      'fields[_add_new_field][widget_type]' => 'entityreference_autocomplete',
 | 
			
		||||
    ), t('Save'));
 | 
			
		||||
 | 
			
		||||
    // Node should be selected by default.
 | 
			
		||||
    $this->assertFieldByName('field[settings][target_type]', 'node');
 | 
			
		||||
    // The base handler should be selected by default.
 | 
			
		||||
    $this->assertFieldByName('field[settings][handler]', 'base');
 | 
			
		||||
 | 
			
		||||
    // The base handler settings should be diplayed.
 | 
			
		||||
    $entity_type = 'node';
 | 
			
		||||
    $entity_info = entity_get_info($entity_type);
 | 
			
		||||
    foreach ($entity_info['bundles'] as $bundle_name => $bundle_info) {
 | 
			
		||||
      $this->assertFieldByName('field[settings][handler_settings][target_bundles][' . $bundle_name . ']');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Test the sort settings.
 | 
			
		||||
    $options = array('none', 'property', 'field');
 | 
			
		||||
    $this->assertFieldSelectOptions('field[settings][handler_settings][sort][type]', $options);
 | 
			
		||||
    // Option 0: no sort.
 | 
			
		||||
    $this->assertFieldByName('field[settings][handler_settings][sort][type]', 'none');
 | 
			
		||||
    $this->assertNoFieldByName('field[settings][handler_settings][sort][property]');
 | 
			
		||||
    $this->assertNoFieldByName('field[settings][handler_settings][sort][field]');
 | 
			
		||||
    $this->assertNoFieldByName('field[settings][handler_settings][sort][direction]');
 | 
			
		||||
    // Option 1: sort by property.
 | 
			
		||||
    $this->drupalPostAJAX(NULL, array('field[settings][handler_settings][sort][type]' => 'property'), 'field[settings][handler_settings][sort][type]');
 | 
			
		||||
    $this->assertFieldByName('field[settings][handler_settings][sort][property]', '');
 | 
			
		||||
    $this->assertNoFieldByName('field[settings][handler_settings][sort][field]');
 | 
			
		||||
    $this->assertFieldByName('field[settings][handler_settings][sort][direction]', 'ASC');
 | 
			
		||||
    // Option 2: sort by field.
 | 
			
		||||
    $this->drupalPostAJAX(NULL, array('field[settings][handler_settings][sort][type]' => 'field'), 'field[settings][handler_settings][sort][type]');
 | 
			
		||||
    $this->assertNoFieldByName('field[settings][handler_settings][sort][property]');
 | 
			
		||||
    $this->assertFieldByName('field[settings][handler_settings][sort][field]', '');
 | 
			
		||||
    $this->assertFieldByName('field[settings][handler_settings][sort][direction]', 'ASC');
 | 
			
		||||
    // Set back to no sort.
 | 
			
		||||
    $this->drupalPostAJAX(NULL, array('field[settings][handler_settings][sort][type]' => 'none'), 'field[settings][handler_settings][sort][type]');
 | 
			
		||||
 | 
			
		||||
    // Second step: 'Instance settings' form.
 | 
			
		||||
    $this->drupalPost(NULL, array(), t('Save field settings'));
 | 
			
		||||
 | 
			
		||||
    // Third step: confirm.
 | 
			
		||||
    $this->drupalPost(NULL, array(), t('Save settings'));
 | 
			
		||||
 | 
			
		||||
    // Check that the field appears in the overview form.
 | 
			
		||||
    $this->assertFieldByXPath('//table[@id="field-overview"]//td[1]', 'Test label', t('Field was created and appears in the overview page.'));
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,575 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @file
 | 
			
		||||
 * Contains EntityReferenceHandlersTestCase
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Test for Entity Reference handlers.
 | 
			
		||||
 */
 | 
			
		||||
class EntityReferenceHandlersTestCase extends DrupalWebTestCase {
 | 
			
		||||
  public static function getInfo() {
 | 
			
		||||
    return array(
 | 
			
		||||
      'name' => 'Entity Reference Handlers',
 | 
			
		||||
      'description' => 'Tests for the base handlers provided by Entity Reference.',
 | 
			
		||||
      'group' => 'Entity Reference',
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function setUp() {
 | 
			
		||||
    parent::setUp('entityreference');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected function assertReferencable($field, $tests, $handler_name) {
 | 
			
		||||
    $handler = entityreference_get_selection_handler($field);
 | 
			
		||||
 | 
			
		||||
    foreach ($tests as $test) {
 | 
			
		||||
      foreach ($test['arguments'] as $arguments) {
 | 
			
		||||
        $result = call_user_func_array(array($handler, 'getReferencableEntities'), $arguments);
 | 
			
		||||
        $this->assertEqual($result, $test['result'], format_string('Valid result set returned by @handler.', array('@handler' => $handler_name)));
 | 
			
		||||
 | 
			
		||||
        $result = call_user_func_array(array($handler, 'countReferencableEntities'), $arguments);
 | 
			
		||||
        if (!empty($test['result'])) {
 | 
			
		||||
          $bundle = key($test['result']);
 | 
			
		||||
          $count = count($test['result'][$bundle]);
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
          $count = 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $this->assertEqual($result, $count, format_string('Valid count returned by @handler.', array('@handler' => $handler_name)));
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Test the node-specific overrides of the entity handler.
 | 
			
		||||
   */
 | 
			
		||||
  public function testNodeHandler() {
 | 
			
		||||
    // Build a fake field instance.
 | 
			
		||||
    $field = array(
 | 
			
		||||
      'translatable' => FALSE,
 | 
			
		||||
      'entity_types' => array(),
 | 
			
		||||
      'settings' => array(
 | 
			
		||||
        'handler' => 'base',
 | 
			
		||||
        'target_type' => 'node',
 | 
			
		||||
        'handler_settings' => array(
 | 
			
		||||
          'target_bundles' => array(),
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
      'field_name' => 'test_field',
 | 
			
		||||
      'type' => 'entityreference',
 | 
			
		||||
      'cardinality' => '1',
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // Build a set of test data.
 | 
			
		||||
    // Titles contain HTML-special characters to test escaping.
 | 
			
		||||
    $nodes = array(
 | 
			
		||||
      'published1' => (object) array(
 | 
			
		||||
        'type' => 'article',
 | 
			
		||||
        'status' => 1,
 | 
			
		||||
        'title' => 'Node published1 (<&>)',
 | 
			
		||||
        'uid' => 1,
 | 
			
		||||
      ),
 | 
			
		||||
      'published2' => (object) array(
 | 
			
		||||
        'type' => 'article',
 | 
			
		||||
        'status' => 1,
 | 
			
		||||
        'title' => 'Node published2 (<&>)',
 | 
			
		||||
        'uid' => 1,
 | 
			
		||||
      ),
 | 
			
		||||
      'unpublished' => (object) array(
 | 
			
		||||
        'type' => 'article',
 | 
			
		||||
        'status' => 0,
 | 
			
		||||
        'title' => 'Node unpublished (<&>)',
 | 
			
		||||
        'uid' => 1,
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    $node_labels = array();
 | 
			
		||||
    foreach ($nodes as $key => $node) {
 | 
			
		||||
      node_save($node);
 | 
			
		||||
      $node_labels[$key] = check_plain($node->title);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Test as a non-admin.
 | 
			
		||||
    $normal_user = $this->drupalCreateUser(array('access content'));
 | 
			
		||||
    $GLOBALS['user'] = $normal_user;
 | 
			
		||||
    $referencable_tests = array(
 | 
			
		||||
      array(
 | 
			
		||||
        'arguments' => array(
 | 
			
		||||
          array(NULL, 'CONTAINS'),
 | 
			
		||||
        ),
 | 
			
		||||
        'result' => array(
 | 
			
		||||
          'article' => array(
 | 
			
		||||
            $nodes['published1']->nid => $node_labels['published1'],
 | 
			
		||||
            $nodes['published2']->nid => $node_labels['published2'],
 | 
			
		||||
          ),
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
      array(
 | 
			
		||||
        'arguments' => array(
 | 
			
		||||
          array('published1', 'CONTAINS'),
 | 
			
		||||
          array('Published1', 'CONTAINS'),
 | 
			
		||||
        ),
 | 
			
		||||
        'result' => array(
 | 
			
		||||
          'article' => array(
 | 
			
		||||
            $nodes['published1']->nid => $node_labels['published1'],
 | 
			
		||||
          ),
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
      array(
 | 
			
		||||
        'arguments' => array(
 | 
			
		||||
          array('published2', 'CONTAINS'),
 | 
			
		||||
          array('Published2', 'CONTAINS'),
 | 
			
		||||
        ),
 | 
			
		||||
        'result' => array(
 | 
			
		||||
          'article' => array(
 | 
			
		||||
            $nodes['published2']->nid => $node_labels['published2'],
 | 
			
		||||
          ),
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
      array(
 | 
			
		||||
        'arguments' => array(
 | 
			
		||||
          array('invalid node', 'CONTAINS'),
 | 
			
		||||
        ),
 | 
			
		||||
        'result' => array(),
 | 
			
		||||
      ),
 | 
			
		||||
      array(
 | 
			
		||||
        'arguments' => array(
 | 
			
		||||
          array('Node unpublished', 'CONTAINS'),
 | 
			
		||||
        ),
 | 
			
		||||
        'result' => array(),
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
    $this->assertReferencable($field, $referencable_tests, 'Node handler');
 | 
			
		||||
 | 
			
		||||
    // Test as an admin.
 | 
			
		||||
    $admin_user = $this->drupalCreateUser(array('access content', 'bypass node access'));
 | 
			
		||||
    $GLOBALS['user'] = $admin_user;
 | 
			
		||||
    $referencable_tests = array(
 | 
			
		||||
      array(
 | 
			
		||||
        'arguments' => array(
 | 
			
		||||
          array(NULL, 'CONTAINS'),
 | 
			
		||||
        ),
 | 
			
		||||
        'result' => array(
 | 
			
		||||
          'article' => array(
 | 
			
		||||
            $nodes['published1']->nid => $node_labels['published1'],
 | 
			
		||||
            $nodes['published2']->nid => $node_labels['published2'],
 | 
			
		||||
            $nodes['unpublished']->nid => $node_labels['unpublished'],
 | 
			
		||||
          ),
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
      array(
 | 
			
		||||
        'arguments' => array(
 | 
			
		||||
          array('Node unpublished', 'CONTAINS'),
 | 
			
		||||
        ),
 | 
			
		||||
        'result' => array(
 | 
			
		||||
          'article' => array(
 | 
			
		||||
            $nodes['unpublished']->nid => $node_labels['unpublished'],
 | 
			
		||||
          ),
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
    $this->assertReferencable($field, $referencable_tests, 'Node handler (admin)');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Test the user-specific overrides of the entity handler.
 | 
			
		||||
   */
 | 
			
		||||
  public function testUserHandler() {
 | 
			
		||||
    // Build a fake field instance.
 | 
			
		||||
    $field = array(
 | 
			
		||||
      'translatable' => FALSE,
 | 
			
		||||
      'entity_types' => array(),
 | 
			
		||||
      'settings' => array(
 | 
			
		||||
        'handler' => 'base',
 | 
			
		||||
        'target_type' => 'user',
 | 
			
		||||
        'handler_settings' => array(
 | 
			
		||||
          'target_bundles' => array(),
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
      'field_name' => 'test_field',
 | 
			
		||||
      'type' => 'entityreference',
 | 
			
		||||
      'cardinality' => '1',
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // Build a set of test data.
 | 
			
		||||
    $users = array(
 | 
			
		||||
      'anonymous' => user_load(0),
 | 
			
		||||
      'admin' => user_load(1),
 | 
			
		||||
      'non_admin' => (object) array(
 | 
			
		||||
        'name' => 'non_admin <&>',
 | 
			
		||||
        'mail' => 'non_admin@example.com',
 | 
			
		||||
        'roles' => array(),
 | 
			
		||||
        'pass' => user_password(),
 | 
			
		||||
        'status' => 1,
 | 
			
		||||
      ),
 | 
			
		||||
      'blocked' => (object) array(
 | 
			
		||||
        'name' => 'blocked <&>',
 | 
			
		||||
        'mail' => 'blocked@example.com',
 | 
			
		||||
        'roles' => array(),
 | 
			
		||||
        'pass' => user_password(),
 | 
			
		||||
        'status' => 0,
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // The label of the anonymous user is variable_get('anonymous').
 | 
			
		||||
    $users['anonymous']->name = variable_get('anonymous', t('Anonymous'));
 | 
			
		||||
 | 
			
		||||
    $user_labels = array();
 | 
			
		||||
    foreach ($users as $key => $user) {
 | 
			
		||||
      if (!isset($user->uid)) {
 | 
			
		||||
        $users[$key] = $user = user_save(drupal_anonymous_user(), (array) $user);
 | 
			
		||||
      }
 | 
			
		||||
      $user_labels[$key] = check_plain($user->name);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Test as a non-admin.
 | 
			
		||||
    $GLOBALS['user'] = $users['non_admin'];
 | 
			
		||||
    $referencable_tests = array(
 | 
			
		||||
      array(
 | 
			
		||||
        'arguments' => array(
 | 
			
		||||
          array(NULL, 'CONTAINS'),
 | 
			
		||||
        ),
 | 
			
		||||
        'result' => array(
 | 
			
		||||
          'user' => array(
 | 
			
		||||
            $users['admin']->uid => $user_labels['admin'],
 | 
			
		||||
            $users['non_admin']->uid => $user_labels['non_admin'],
 | 
			
		||||
          ),
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
      array(
 | 
			
		||||
        'arguments' => array(
 | 
			
		||||
          array('non_admin', 'CONTAINS'),
 | 
			
		||||
          array('NON_ADMIN', 'CONTAINS'),
 | 
			
		||||
        ),
 | 
			
		||||
        'result' => array(
 | 
			
		||||
          'user' => array(
 | 
			
		||||
            $users['non_admin']->uid => $user_labels['non_admin'],
 | 
			
		||||
          ),
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
      array(
 | 
			
		||||
        'arguments' => array(
 | 
			
		||||
          array('invalid user', 'CONTAINS'),
 | 
			
		||||
        ),
 | 
			
		||||
        'result' => array(),
 | 
			
		||||
      ),
 | 
			
		||||
      array(
 | 
			
		||||
        'arguments' => array(
 | 
			
		||||
          array('blocked', 'CONTAINS'),
 | 
			
		||||
        ),
 | 
			
		||||
        'result' => array(),
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
    $this->assertReferencable($field, $referencable_tests, 'User handler');
 | 
			
		||||
 | 
			
		||||
    $GLOBALS['user'] = $users['admin'];
 | 
			
		||||
    $referencable_tests = array(
 | 
			
		||||
      array(
 | 
			
		||||
        'arguments' => array(
 | 
			
		||||
          array(NULL, 'CONTAINS'),
 | 
			
		||||
        ),
 | 
			
		||||
        'result' => array(
 | 
			
		||||
          'user' => array(
 | 
			
		||||
            $users['anonymous']->uid => $user_labels['anonymous'],
 | 
			
		||||
            $users['admin']->uid => $user_labels['admin'],
 | 
			
		||||
            $users['non_admin']->uid => $user_labels['non_admin'],
 | 
			
		||||
            $users['blocked']->uid => $user_labels['blocked'],
 | 
			
		||||
          ),
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
      array(
 | 
			
		||||
        'arguments' => array(
 | 
			
		||||
          array('blocked', 'CONTAINS'),
 | 
			
		||||
        ),
 | 
			
		||||
        'result' => array(
 | 
			
		||||
          'user' => array(
 | 
			
		||||
            $users['blocked']->uid => $user_labels['blocked'],
 | 
			
		||||
          ),
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
      array(
 | 
			
		||||
        'arguments' => array(
 | 
			
		||||
          array('Anonymous', 'CONTAINS'),
 | 
			
		||||
          array('anonymous', 'CONTAINS'),
 | 
			
		||||
        ),
 | 
			
		||||
        'result' => array(
 | 
			
		||||
          'user' => array(
 | 
			
		||||
            $users['anonymous']->uid => $user_labels['anonymous'],
 | 
			
		||||
          ),
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
    $this->assertReferencable($field, $referencable_tests, 'User handler (admin)');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Test the comment-specific overrides of the entity handler.
 | 
			
		||||
   */
 | 
			
		||||
  public function testCommentHandler() {
 | 
			
		||||
    // Build a fake field instance.
 | 
			
		||||
    $field = array(
 | 
			
		||||
      'translatable' => FALSE,
 | 
			
		||||
      'entity_types' => array(),
 | 
			
		||||
      'settings' => array(
 | 
			
		||||
        'handler' => 'base',
 | 
			
		||||
        'target_type' => 'comment',
 | 
			
		||||
        'handler_settings' => array(
 | 
			
		||||
          'target_bundles' => array(),
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
      'field_name' => 'test_field',
 | 
			
		||||
      'type' => 'entityreference',
 | 
			
		||||
      'cardinality' => '1',
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // Build a set of test data.
 | 
			
		||||
    $nodes = array(
 | 
			
		||||
      'published' => (object) array(
 | 
			
		||||
        'type' => 'article',
 | 
			
		||||
        'status' => 1,
 | 
			
		||||
        'title' => 'Node published',
 | 
			
		||||
        'uid' => 1,
 | 
			
		||||
      ),
 | 
			
		||||
      'unpublished' => (object) array(
 | 
			
		||||
        'type' => 'article',
 | 
			
		||||
        'status' => 0,
 | 
			
		||||
        'title' => 'Node unpublished',
 | 
			
		||||
        'uid' => 1,
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
    foreach ($nodes as $node) {
 | 
			
		||||
      node_save($node);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $comments = array(
 | 
			
		||||
      'published_published' => (object) array(
 | 
			
		||||
        'nid' => $nodes['published']->nid,
 | 
			
		||||
        'uid' => 1,
 | 
			
		||||
        'cid' => NULL,
 | 
			
		||||
        'pid' => 0,
 | 
			
		||||
        'status' => COMMENT_PUBLISHED,
 | 
			
		||||
        'subject' => 'Comment Published <&>',
 | 
			
		||||
        'hostname' => ip_address(),
 | 
			
		||||
        'language' => LANGUAGE_NONE,
 | 
			
		||||
      ),
 | 
			
		||||
      'published_unpublished' => (object) array(
 | 
			
		||||
        'nid' => $nodes['published']->nid,
 | 
			
		||||
        'uid' => 1,
 | 
			
		||||
        'cid' => NULL,
 | 
			
		||||
        'pid' => 0,
 | 
			
		||||
        'status' => COMMENT_NOT_PUBLISHED,
 | 
			
		||||
        'subject' => 'Comment Unpublished <&>',
 | 
			
		||||
        'hostname' => ip_address(),
 | 
			
		||||
        'language' => LANGUAGE_NONE,
 | 
			
		||||
      ),
 | 
			
		||||
      'unpublished_published' => (object) array(
 | 
			
		||||
        'nid' => $nodes['unpublished']->nid,
 | 
			
		||||
        'uid' => 1,
 | 
			
		||||
        'cid' => NULL,
 | 
			
		||||
        'pid' => 0,
 | 
			
		||||
        'status' => COMMENT_NOT_PUBLISHED,
 | 
			
		||||
        'subject' => 'Comment Published on Unpublished node <&>',
 | 
			
		||||
        'hostname' => ip_address(),
 | 
			
		||||
        'language' => LANGUAGE_NONE,
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    $comment_labels = array();
 | 
			
		||||
    foreach ($comments as $key => $comment) {
 | 
			
		||||
      comment_save($comment);
 | 
			
		||||
      $comment_labels[$key] = check_plain($comment->subject);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Test as a non-admin.
 | 
			
		||||
    $normal_user = $this->drupalCreateUser(array('access content', 'access comments'));
 | 
			
		||||
    $GLOBALS['user'] = $normal_user;
 | 
			
		||||
    $referencable_tests = array(
 | 
			
		||||
      array(
 | 
			
		||||
        'arguments' => array(
 | 
			
		||||
          array(NULL, 'CONTAINS'),
 | 
			
		||||
        ),
 | 
			
		||||
        'result' => array(
 | 
			
		||||
          'comment_node_article' => array(
 | 
			
		||||
            $comments['published_published']->cid => $comment_labels['published_published'],
 | 
			
		||||
          ),
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
      array(
 | 
			
		||||
        'arguments' => array(
 | 
			
		||||
          array('Published', 'CONTAINS'),
 | 
			
		||||
        ),
 | 
			
		||||
        'result' => array(
 | 
			
		||||
          'comment_node_article' => array(
 | 
			
		||||
            $comments['published_published']->cid => $comment_labels['published_published'],
 | 
			
		||||
          ),
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
      array(
 | 
			
		||||
        'arguments' => array(
 | 
			
		||||
          array('invalid comment', 'CONTAINS'),
 | 
			
		||||
        ),
 | 
			
		||||
        'result' => array(),
 | 
			
		||||
      ),
 | 
			
		||||
      array(
 | 
			
		||||
        'arguments' => array(
 | 
			
		||||
          array('Comment Unpublished', 'CONTAINS'),
 | 
			
		||||
        ),
 | 
			
		||||
        'result' => array(),
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
    $this->assertReferencable($field, $referencable_tests, 'Comment handler');
 | 
			
		||||
 | 
			
		||||
    // Test as a comment admin.
 | 
			
		||||
    $admin_user = $this->drupalCreateUser(array('access content', 'access comments', 'administer comments'));
 | 
			
		||||
    $GLOBALS['user'] = $admin_user;
 | 
			
		||||
    $referencable_tests = array(
 | 
			
		||||
      array(
 | 
			
		||||
        'arguments' => array(
 | 
			
		||||
          array(NULL, 'CONTAINS'),
 | 
			
		||||
        ),
 | 
			
		||||
        'result' => array(
 | 
			
		||||
          'comment_node_article' => array(
 | 
			
		||||
            $comments['published_published']->cid => $comment_labels['published_published'],
 | 
			
		||||
            $comments['published_unpublished']->cid => $comment_labels['published_unpublished'],
 | 
			
		||||
          ),
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
    $this->assertReferencable($field, $referencable_tests, 'Comment handler (comment admin)');
 | 
			
		||||
 | 
			
		||||
    // Test as a node and comment admin.
 | 
			
		||||
    $admin_user = $this->drupalCreateUser(array('access content', 'access comments', 'administer comments', 'bypass node access'));
 | 
			
		||||
    $GLOBALS['user'] = $admin_user;
 | 
			
		||||
    $referencable_tests = array(
 | 
			
		||||
      array(
 | 
			
		||||
        'arguments' => array(
 | 
			
		||||
          array(NULL, 'CONTAINS'),
 | 
			
		||||
        ),
 | 
			
		||||
        'result' => array(
 | 
			
		||||
          'comment_node_article' => array(
 | 
			
		||||
            $comments['published_published']->cid => $comment_labels['published_published'],
 | 
			
		||||
            $comments['published_unpublished']->cid => $comment_labels['published_unpublished'],
 | 
			
		||||
            $comments['unpublished_published']->cid => $comment_labels['unpublished_published'],
 | 
			
		||||
          ),
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
    $this->assertReferencable($field, $referencable_tests, 'Comment handler (comment + node admin)');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Assert sorting by field works for non-admins.
 | 
			
		||||
   *
 | 
			
		||||
   * Since we are sorting on a field, we need to make sure the base-table
 | 
			
		||||
   * is added, and access-control is behaving as expected.
 | 
			
		||||
   */
 | 
			
		||||
  public function testSortByField() {
 | 
			
		||||
    // Add text field to entity, to sort by.
 | 
			
		||||
    $field_info = array(
 | 
			
		||||
      'field_name' => 'field_text',
 | 
			
		||||
      'type' => 'text',
 | 
			
		||||
      'entity_types' => array('node'),
 | 
			
		||||
    );
 | 
			
		||||
    field_create_field($field_info);
 | 
			
		||||
 | 
			
		||||
    $instance = array(
 | 
			
		||||
      'label' => 'Text Field',
 | 
			
		||||
      'field_name' => 'field_text',
 | 
			
		||||
      'entity_type' => 'node',
 | 
			
		||||
      'bundle' => 'article',
 | 
			
		||||
      'settings' => array(),
 | 
			
		||||
      'required' => FALSE,
 | 
			
		||||
    );
 | 
			
		||||
    field_create_instance($instance);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // Build a fake field instance.
 | 
			
		||||
    $field = array(
 | 
			
		||||
      'translatable' => FALSE,
 | 
			
		||||
      'entity_types' => array(),
 | 
			
		||||
      'settings' => array(
 | 
			
		||||
        'handler' => 'base',
 | 
			
		||||
        'target_type' => 'node',
 | 
			
		||||
        'handler_settings' => array(
 | 
			
		||||
          'target_bundles' => array(),
 | 
			
		||||
          // Add sorting.
 | 
			
		||||
          'sort' => array(
 | 
			
		||||
            'type' => 'field',
 | 
			
		||||
            'field' => 'field_text:value',
 | 
			
		||||
            'direction' => 'DESC',
 | 
			
		||||
          ),
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
      'field_name' => 'test_field',
 | 
			
		||||
      'type' => 'entityreference',
 | 
			
		||||
      'cardinality' => '1',
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // Build a set of test data.
 | 
			
		||||
    $nodes = array(
 | 
			
		||||
      'published1' => (object) array(
 | 
			
		||||
        'type' => 'article',
 | 
			
		||||
        'status' => 1,
 | 
			
		||||
        'title' => 'Node published1 (<&>)',
 | 
			
		||||
        'uid' => 1,
 | 
			
		||||
        'field_text' => array(
 | 
			
		||||
          LANGUAGE_NONE => array(
 | 
			
		||||
            array(
 | 
			
		||||
              'value' => 1,
 | 
			
		||||
            ),
 | 
			
		||||
          ),
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
      'published2' => (object) array(
 | 
			
		||||
        'type' => 'article',
 | 
			
		||||
        'status' => 1,
 | 
			
		||||
        'title' => 'Node published2 (<&>)',
 | 
			
		||||
        'uid' => 1,
 | 
			
		||||
        'field_text' => array(
 | 
			
		||||
          LANGUAGE_NONE => array(
 | 
			
		||||
            array(
 | 
			
		||||
              'value' => 2,
 | 
			
		||||
            ),
 | 
			
		||||
          ),
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
      'unpublished' => (object) array(
 | 
			
		||||
        'type' => 'article',
 | 
			
		||||
        'status' => 0,
 | 
			
		||||
        'title' => 'Node unpublished (<&>)',
 | 
			
		||||
        'uid' => 1,
 | 
			
		||||
        'field_text' => array(
 | 
			
		||||
          LANGUAGE_NONE => array(
 | 
			
		||||
            array(
 | 
			
		||||
              'value' => 3,
 | 
			
		||||
            ),
 | 
			
		||||
          ),
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    $node_labels = array();
 | 
			
		||||
    foreach ($nodes as $key => $node) {
 | 
			
		||||
      node_save($node);
 | 
			
		||||
      $node_labels[$key] = check_plain($node->title);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Test as a non-admin.
 | 
			
		||||
    $normal_user = $this->drupalCreateUser(array('access content'));
 | 
			
		||||
    $GLOBALS['user'] = $normal_user;
 | 
			
		||||
 | 
			
		||||
    $handler = entityreference_get_selection_handler($field);
 | 
			
		||||
 | 
			
		||||
    // Not only assert the result, but make sure the keys are sorted as
 | 
			
		||||
    // expected.
 | 
			
		||||
    $result = $handler->getReferencableEntities();
 | 
			
		||||
    $expected_result = array(
 | 
			
		||||
      $nodes['published2']->nid => $node_labels['published2'],
 | 
			
		||||
      $nodes['published1']->nid => $node_labels['published1'],
 | 
			
		||||
    );
 | 
			
		||||
    $this->assertIdentical($result['article'], $expected_result, 'Query sorted by field returned expected values for non-admin.');
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,115 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Test for Entity Reference taxonomy integration.
 | 
			
		||||
 */
 | 
			
		||||
class EntityReferenceTaxonomyTestCase extends DrupalWebTestCase {
 | 
			
		||||
  public static function getInfo() {
 | 
			
		||||
    return array(
 | 
			
		||||
      'name' => 'Entity Reference Taxonomy',
 | 
			
		||||
      'description' => 'Tests nodes with reference to terms as indexed.',
 | 
			
		||||
      'group' => 'Entity Reference',
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function setUp() {
 | 
			
		||||
    parent::setUp('entityreference', 'taxonomy');
 | 
			
		||||
 | 
			
		||||
    // Create an entity reference field.
 | 
			
		||||
    $field = array(
 | 
			
		||||
      'entity_types' => array('node'),
 | 
			
		||||
      'settings' => array(
 | 
			
		||||
        'handler' => 'base',
 | 
			
		||||
        'target_type' => 'taxonomy_term',
 | 
			
		||||
        'handler_settings' => array(
 | 
			
		||||
          'target_bundles' => array(),
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
      'field_name' => 'field_entityreference_term',
 | 
			
		||||
      'type' => 'entityreference',
 | 
			
		||||
    );
 | 
			
		||||
    $field = field_create_field($field);
 | 
			
		||||
    $instance = array(
 | 
			
		||||
      'field_name' => 'field_entityreference_term',
 | 
			
		||||
      'bundle' => 'article',
 | 
			
		||||
      'entity_type' => 'node',
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // Enable the taxonomy-index behavior.
 | 
			
		||||
    $instance['settings']['behaviors']['taxonomy-index']['status'] = TRUE;
 | 
			
		||||
    field_create_instance($instance);
 | 
			
		||||
 | 
			
		||||
    // Create a term reference field.
 | 
			
		||||
    $field = array(
 | 
			
		||||
      'translatable' => FALSE,
 | 
			
		||||
      'entity_types' => array('node'),
 | 
			
		||||
      'settings' => array(
 | 
			
		||||
        'allowed_values' => array(
 | 
			
		||||
          array(
 | 
			
		||||
            'vocabulary' => 'terms',
 | 
			
		||||
            'parent' => 0,
 | 
			
		||||
          ),
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
      'field_name' => 'field_taxonomy_term',
 | 
			
		||||
      'type' => 'taxonomy_term_reference',
 | 
			
		||||
    );
 | 
			
		||||
    $field = field_create_field($field);
 | 
			
		||||
    $instance = array(
 | 
			
		||||
      'field_name' => 'field_taxonomy_term',
 | 
			
		||||
      'bundle' => 'article',
 | 
			
		||||
      'entity_type' => 'node',
 | 
			
		||||
    );
 | 
			
		||||
    field_create_instance($instance);
 | 
			
		||||
 | 
			
		||||
    // Create a terms vocobulary.
 | 
			
		||||
    $vocabulary = new stdClass();
 | 
			
		||||
    $vocabulary->name = 'Terms';
 | 
			
		||||
    $vocabulary->machine_name = 'terms';
 | 
			
		||||
    taxonomy_vocabulary_save($vocabulary);
 | 
			
		||||
 | 
			
		||||
    // Create term.
 | 
			
		||||
    for ($i = 1; $i <= 2; $i++) {
 | 
			
		||||
      $term = new stdClass();
 | 
			
		||||
      $term->name = "term $i";
 | 
			
		||||
      $term->vid = 1;
 | 
			
		||||
      taxonomy_term_save($term);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Test referencing a term using entity reference field.
 | 
			
		||||
   */
 | 
			
		||||
  public function testNodeIndex() {
 | 
			
		||||
    // Asert node insert with reference to term.
 | 
			
		||||
    $settings = array();
 | 
			
		||||
    $settings['type'] = 'article';
 | 
			
		||||
    $settings['field_entityreference_term'][LANGUAGE_NONE][0]['target_id'] = 1;
 | 
			
		||||
    $node = $this->drupalCreateNode($settings);
 | 
			
		||||
 | 
			
		||||
    $this->assertEqual(taxonomy_select_nodes(1), array($node->nid));
 | 
			
		||||
 | 
			
		||||
    // Asert node update with reference to term.
 | 
			
		||||
    node_save($node);
 | 
			
		||||
    $this->assertEqual(taxonomy_select_nodes(1), array($node->nid));
 | 
			
		||||
 | 
			
		||||
    // Assert node update with reference to term and taxonomy reference to
 | 
			
		||||
    // another term.
 | 
			
		||||
    $wrapper = entity_metadata_wrapper('node', $node);
 | 
			
		||||
    $wrapper->field_taxonomy_term->set(2);
 | 
			
		||||
    $wrapper->save();
 | 
			
		||||
 | 
			
		||||
    $this->assertEqual(taxonomy_select_nodes(1), array($node->nid));
 | 
			
		||||
    $this->assertEqual(taxonomy_select_nodes(2), array($node->nid));
 | 
			
		||||
 | 
			
		||||
    // Assert node update with reference to term and taxonomy reference to
 | 
			
		||||
    // same term.
 | 
			
		||||
    $wrapper->field_taxonomy_term->set(1);
 | 
			
		||||
    $wrapper->save();
 | 
			
		||||
    $this->assertEqual(taxonomy_select_nodes(1), array($node->nid));
 | 
			
		||||
 | 
			
		||||
    $wrapper->delete();
 | 
			
		||||
    $this->assertFalse(taxonomy_select_nodes(1));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,136 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @file
 | 
			
		||||
 * Views integration for Entity Reference.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Implements hook_field_views_data().
 | 
			
		||||
 */
 | 
			
		||||
function entityreference_field_views_data($field) {
 | 
			
		||||
  $data = field_views_field_default_views_data($field);
 | 
			
		||||
  $entity_info = entity_get_info($field['settings']['target_type']);
 | 
			
		||||
  foreach ($data as $table_name => $table_data) {
 | 
			
		||||
    if (isset($entity_info['base table'])) {
 | 
			
		||||
      $entity = $entity_info['label'];
 | 
			
		||||
      if ($entity == t('Node')) {
 | 
			
		||||
        $entity = t('Content');
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      $field_name = $field['field_name'] . '_target_id';
 | 
			
		||||
      $parameters = array('@entity' => $entity, '!field_name' => $field['field_name']);
 | 
			
		||||
      $data[$table_name][$field_name]['relationship'] = array(
 | 
			
		||||
        'handler' => 'views_handler_relationship',
 | 
			
		||||
        'base' => $entity_info['base table'],
 | 
			
		||||
        'base field' => $entity_info['entity keys']['id'],
 | 
			
		||||
        'label' => t('@entity entity referenced from !field_name', $parameters),
 | 
			
		||||
        'group' => t('Entity Reference'),
 | 
			
		||||
        'title' => t('Referenced Entity'),
 | 
			
		||||
        'help' => t('A bridge to the @entity entity that is referenced via !field_name', $parameters),
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Invoke the behaviors to allow them to change the properties.
 | 
			
		||||
  foreach (entityreference_get_behavior_handlers($field) as $handler) {
 | 
			
		||||
    $handler->views_data_alter($data, $field);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return $data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Options callback for Views handler views_handler_filter_in_operator.
 | 
			
		||||
 */
 | 
			
		||||
function entityreference_views_handler_options_list($field_name) {
 | 
			
		||||
  $field = field_info_field($field_name);
 | 
			
		||||
  return entityreference_options_list($field);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Implements hook_field_views_data_views_data_alter().
 | 
			
		||||
 *
 | 
			
		||||
 * Views integration to provide reverse relationships on entityreference fields.
 | 
			
		||||
 */
 | 
			
		||||
function entityreference_field_views_data_views_data_alter(&$data, $field) {
 | 
			
		||||
  foreach ($field['bundles'] as $entity_type => $bundles) {
 | 
			
		||||
    $target_entity_info = entity_get_info($field['settings']['target_type']);
 | 
			
		||||
    if (isset($target_entity_info['base table'])) {
 | 
			
		||||
      $entity_info = entity_get_info($entity_type);
 | 
			
		||||
      $entity = $entity_info['label'];
 | 
			
		||||
      if ($entity == t('Node')) {
 | 
			
		||||
        $entity = t('Content');
 | 
			
		||||
      }
 | 
			
		||||
      $target_entity = $target_entity_info['label'];
 | 
			
		||||
      if ($target_entity == t('Node')) {
 | 
			
		||||
        $target_entity = t('Content');
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      $pseudo_field_name = 'reverse_' . $field['field_name'] . '_' . $entity_type;
 | 
			
		||||
      $replacements = array('@entity' => $entity, '@target_entity' => $target_entity, '!field_name' => $field['field_name']);
 | 
			
		||||
      $data[$target_entity_info['base table']][$pseudo_field_name]['relationship'] = array(
 | 
			
		||||
        'handler' => 'views_handler_relationship_entity_reverse',
 | 
			
		||||
        'field_name' => $field['field_name'],
 | 
			
		||||
        'field table' => _field_sql_storage_tablename($field),
 | 
			
		||||
        'field field' => $field['field_name'] . '_target_id',
 | 
			
		||||
        'base' => $entity_info['base table'],
 | 
			
		||||
        'base field' => $entity_info['entity keys']['id'],
 | 
			
		||||
        'label' => t('@entity referencing @target_entity from !field_name', $replacements),
 | 
			
		||||
        'group' => t('Entity Reference'),
 | 
			
		||||
        'title' => t('Referencing entity'),
 | 
			
		||||
        'help' => t('A bridge to the @entity entity that is referencing @target_entity via !field_name', $replacements),
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Implements hook_views_plugins().
 | 
			
		||||
 */
 | 
			
		||||
function entityreference_views_plugins() {
 | 
			
		||||
  $plugins = array(
 | 
			
		||||
    'display' => array(
 | 
			
		||||
      'entityreference' => array(
 | 
			
		||||
        'title' => t('Entity Reference'),
 | 
			
		||||
        'admin' => t('Entity Reference Source'),
 | 
			
		||||
        'help' => 'Selects referenceable entities for an entity reference field',
 | 
			
		||||
        'handler' => 'entityreference_plugin_display',
 | 
			
		||||
        'uses hook menu' => FALSE,
 | 
			
		||||
        'use ajax' => FALSE,
 | 
			
		||||
        'use pager' => FALSE,
 | 
			
		||||
        'accept attachments' => FALSE,
 | 
			
		||||
        // Custom property, used with views_get_applicable_views() to retrieve
 | 
			
		||||
        // all views with a 'Entity Reference' display.
 | 
			
		||||
        'entityreference display' => TRUE,
 | 
			
		||||
      ),
 | 
			
		||||
    ),
 | 
			
		||||
    'style' => array(
 | 
			
		||||
      'entityreference_style' => array(
 | 
			
		||||
        'title' => t('Entity Reference list'),
 | 
			
		||||
        'help' => 'Returns results as a PHP array of labels and rendered rows.',
 | 
			
		||||
        'handler' => 'entityreference_plugin_style',
 | 
			
		||||
        'theme' => 'views_view_unformatted',
 | 
			
		||||
        'uses row plugin' => TRUE,
 | 
			
		||||
        'uses fields' => TRUE,
 | 
			
		||||
        'uses options' => TRUE,
 | 
			
		||||
        'type' => 'entityreference',
 | 
			
		||||
        'even empty' => TRUE,
 | 
			
		||||
      ),
 | 
			
		||||
    ),
 | 
			
		||||
    'row' => array(
 | 
			
		||||
      'entityreference_fields' => array(
 | 
			
		||||
        'title' => t('Inline fields'),
 | 
			
		||||
        'help' => t('Displays the fields with an optional template.'),
 | 
			
		||||
        'handler' => 'entityreference_plugin_row_fields',
 | 
			
		||||
        'theme' => 'views_view_fields',
 | 
			
		||||
        'theme path' => drupal_get_path('module', 'views') . '/theme',
 | 
			
		||||
        'theme file' => 'theme.inc',
 | 
			
		||||
        'uses fields' => TRUE,
 | 
			
		||||
        'uses options' => TRUE,
 | 
			
		||||
        'type' => 'entityreference',
 | 
			
		||||
      ),
 | 
			
		||||
    ),
 | 
			
		||||
  );
 | 
			
		||||
  return $plugins;
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,123 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @file
 | 
			
		||||
 * Handler for entityreference_plugin_display.
 | 
			
		||||
 */
 | 
			
		||||
class entityreference_plugin_display extends views_plugin_display {
 | 
			
		||||
 | 
			
		||||
  function option_definition() {
 | 
			
		||||
    $options = parent::option_definition();
 | 
			
		||||
 | 
			
		||||
    // Force the style plugin to 'entityreference_style' and the row plugin to
 | 
			
		||||
    // 'fields'.
 | 
			
		||||
    $options['style_plugin']['default'] = 'entityreference_style';
 | 
			
		||||
    $options['defaults']['default']['style_plugin'] = FALSE;
 | 
			
		||||
    $options['defaults']['default']['style_options'] = FALSE;
 | 
			
		||||
    $options['row_plugin']['default'] = 'entityreference_fields';
 | 
			
		||||
    $options['defaults']['default']['row_plugin'] = FALSE;
 | 
			
		||||
    $options['defaults']['default']['row_options'] = FALSE;
 | 
			
		||||
 | 
			
		||||
    // Set the display title to an empty string (not used in this display type).
 | 
			
		||||
    $options['title']['default'] = '';
 | 
			
		||||
    $options['defaults']['default']['title'] = FALSE;
 | 
			
		||||
 | 
			
		||||
    return $options;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function get_style_type() {
 | 
			
		||||
    return 'entityreference';
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function execute() {
 | 
			
		||||
    return $this->view->render($this->display->id);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function render() {
 | 
			
		||||
    if (!empty($this->view->result) || !empty($this->view->style_plugin->definition['even empty'])) {
 | 
			
		||||
      return $this->view->style_plugin->render($this->view->result);
 | 
			
		||||
    }
 | 
			
		||||
    return '';
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function uses_exposed() {
 | 
			
		||||
    return FALSE;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function query() {
 | 
			
		||||
    $options = $this->get_option('entityreference_options');
 | 
			
		||||
 | 
			
		||||
    // Play nice with Views UI 'preview' : if the view is not executed through
 | 
			
		||||
    // EntityReference_SelectionHandler_Views::getReferencableEntities(),
 | 
			
		||||
    // don't alter the query.
 | 
			
		||||
    if (empty($options)) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Make sure the id field is included in the results, and save its alias
 | 
			
		||||
    // so that references_plugin_style can retrieve it.
 | 
			
		||||
    $this->id_field_alias = $id_field = $this->view->query->add_field($this->view->base_table, $this->view->base_field);
 | 
			
		||||
    if (strpos($id_field, '.') === FALSE) {
 | 
			
		||||
      $id_field = $this->view->base_table . '.' . $this->id_field_alias;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Restrict the autocomplete options based on what's been typed already.
 | 
			
		||||
    if (isset($options['match'])) {
 | 
			
		||||
      $style_options = $this->get_option('style_options');
 | 
			
		||||
      $value = db_like($options['match']) . '%';
 | 
			
		||||
      if ($options['match_operator'] != 'STARTS_WITH') {
 | 
			
		||||
        $value = '%' . $value;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // Multiple search fields are OR'd together
 | 
			
		||||
      $conditions = db_or();
 | 
			
		||||
 | 
			
		||||
      // Build the condition using the selected search fields
 | 
			
		||||
      foreach ($style_options['search_fields'] as $field_alias) {
 | 
			
		||||
        if (!empty($field_alias)) {
 | 
			
		||||
          // Get the table and field names for the checked field
 | 
			
		||||
          if (empty($this->view->field[$field_alias]->field_info)) 
 | 
			
		||||
            $field = $this->view->query->fields[$this->view->field[$field_alias]->field_alias];
 | 
			
		||||
          else {
 | 
			
		||||
            $this->view->query->add_field($this->view->field[$field_alias]->options['table'], $this->view->field[$field_alias]->real_field, $this->view->field[$field_alias]->options['field'], array());
 | 
			
		||||
            $field = $this->view->query->fields[$this->view->field[$field_alias]->options['field']];
 | 
			
		||||
          }
 | 
			
		||||
          // Add an OR condition for the field
 | 
			
		||||
          $conditions->condition($field['table'] . '.' . $field['field'], $value, 'LIKE');
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      $this->view->query->add_where(NULL, $conditions);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Add an IN condition for validation.
 | 
			
		||||
    if (!empty($options['ids'])) {
 | 
			
		||||
      $this->view->query->add_where(NULL, $id_field, $options['ids']);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $this->view->set_items_per_page($options['limit']);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Extend the default validation.
 | 
			
		||||
   */
 | 
			
		||||
  function validate() {
 | 
			
		||||
    $errors = parent::validate();
 | 
			
		||||
    // Verify that search fields are set up.
 | 
			
		||||
    $style_options = $this->get_option('style_options');
 | 
			
		||||
    if (!isset($style_options['search_fields'])) {
 | 
			
		||||
      $errors[] = t('Display "@display" needs a selected search fields to work properly. See the settings for the Entity Reference list format.', array('@display' => $this->display->display_title));
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
      // Verify that the search fields used actually exist.
 | 
			
		||||
      //$fields = array_keys($this->view->get_items('field'));
 | 
			
		||||
      $fields = array_keys($this->handlers['field']);
 | 
			
		||||
      foreach ($style_options['search_fields'] as $field_alias => $enabled) {
 | 
			
		||||
        if ($enabled && !in_array($field_alias, $fields)) {
 | 
			
		||||
          $errors[] = t('Display "@display" uses field %field as search field, but the field is no longer present. See the settings for the Entity Reference list format.', array('@display' => $this->display->display_title, '%field' => $field_alias));
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return $errors;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,36 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @file
 | 
			
		||||
 * Handler for entityreference_plugin_row_fields.
 | 
			
		||||
 */
 | 
			
		||||
class entityreference_plugin_row_fields extends views_plugin_row_fields {
 | 
			
		||||
 | 
			
		||||
  function option_definition() {
 | 
			
		||||
    $options = parent::option_definition();
 | 
			
		||||
 | 
			
		||||
    $options['separator'] = array('default' => '-');
 | 
			
		||||
 | 
			
		||||
    return $options;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Provide a form for setting options.
 | 
			
		||||
   */
 | 
			
		||||
  function options_form(&$form, &$form_state) {
 | 
			
		||||
    parent::options_form($form, $form_state);
 | 
			
		||||
 | 
			
		||||
    // Expand the description of the 'Inline field' checkboxes.
 | 
			
		||||
    $form['inline']['#description'] .= '<br />' . t("<strong>Note:</strong> In 'Entity Reference' displays, all fields will be displayed inline unless an explicit selection of inline fields is made here." );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function pre_render($row) {
 | 
			
		||||
    // Force all fields to be inline by default.
 | 
			
		||||
    if (empty($this->options['inline'])) {
 | 
			
		||||
      $fields = $this->view->get_items('field', $this->display->id);
 | 
			
		||||
      $this->options['inline'] = drupal_map_assoc(array_keys($fields));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return parent::pre_render($row);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,66 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @file
 | 
			
		||||
 * Handler for entityreference_plugin_style.
 | 
			
		||||
 */
 | 
			
		||||
class entityreference_plugin_style extends views_plugin_style {
 | 
			
		||||
 | 
			
		||||
  function option_definition() {
 | 
			
		||||
    $options = parent::option_definition();
 | 
			
		||||
    $options['search_fields'] = array('default' => NULL);
 | 
			
		||||
 | 
			
		||||
    return $options;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Create the options form.
 | 
			
		||||
  function options_form(&$form, &$form_state) {
 | 
			
		||||
    parent::options_form($form, $form_state);
 | 
			
		||||
    $options = array();
 | 
			
		||||
 | 
			
		||||
    if (isset($form['grouping'])) {
 | 
			
		||||
      $options = $form['grouping'][0]['field']['#options'];
 | 
			
		||||
      unset($options['']);
 | 
			
		||||
      $form['search_fields'] = array(
 | 
			
		||||
        '#type' => 'checkboxes',
 | 
			
		||||
        '#title' => t('Search fields'),
 | 
			
		||||
        '#options' => $options,
 | 
			
		||||
        '#required' => TRUE,
 | 
			
		||||
        '#default_value' => $this->options['search_fields'],
 | 
			
		||||
        '#description' => t('Select the field(s) that will be searched when using the autocomplete widget.'),
 | 
			
		||||
        '#weight' => -3,
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function render() {
 | 
			
		||||
    $options = $this->display->handler->get_option('entityreference_options');
 | 
			
		||||
 | 
			
		||||
    // Play nice with Views UI 'preview' : if the view is not executed through
 | 
			
		||||
    // EntityReference_SelectionHandler_Views::getReferencableEntities(), just
 | 
			
		||||
    // display the HTML.
 | 
			
		||||
    if (empty($options)) {
 | 
			
		||||
      return parent::render();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Group the rows according to the grouping field, if specified.
 | 
			
		||||
    $sets = $this->render_grouping($this->view->result, $this->options['grouping']);
 | 
			
		||||
 | 
			
		||||
    // Grab the alias of the 'id' field added by entityreference_plugin_display.
 | 
			
		||||
    $id_field_alias = $this->display->handler->id_field_alias;
 | 
			
		||||
 | 
			
		||||
    // @todo We don't display grouping info for now. Could be useful for select
 | 
			
		||||
    // widget, though.
 | 
			
		||||
    $results = array();
 | 
			
		||||
    $this->view->row_index = 0;
 | 
			
		||||
    foreach ($sets as $records) {
 | 
			
		||||
      foreach ($records as $values) {
 | 
			
		||||
        // Sanitize html, remove line breaks and extra whitespace.
 | 
			
		||||
        $results[$values->{$id_field_alias}] = filter_xss_admin(preg_replace('/\s\s+/', ' ', str_replace("\n", '', $this->row_plugin->render($values))));
 | 
			
		||||
        $this->view->row_index++;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    unset($this->view->row_index);
 | 
			
		||||
    return $results;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user