Motivation

I want to make generic solution to check entity uniqueness.
It is common that for example you dont want two taxonomy terms with the same name

Existing solutions like Taxonomy unique or Unique field works only with specified entity types like just for taxonomy term or just for nodes. I believe this is not Drupal evolving direction. Drupal use Entities so contributed modules should work with as many entitie types as possible.

Furthermore existing modules only check entity uniqueness on form validation. So it is useless on to prevent creating duplicate entities programmatically example on entity import. I solved that issue by using hook_entity_presave.

About me

I have 31 years. I love programming. I am self learner. First website I done 16 years ago. I am with Drupal since version 5. I want to develop custom modules to improve my programming skills and API understanding. Also i work with Drupal every day so i need generic solutions that will save my time in site building.

Project page

https://www.drupal.org/sandbox/nimek/2704251

Git command

git clone --branch 7.x-1.x https://git.drupal.org/sandbox/nimek/2704251.git entity_unique

Manual reviews of other projets

https://www.drupal.org/node/2706963#comment-11090753

CommentFileSizeAuthor
#19 2706231-spelling-fixes-19.patch3.95 KBalex.skrypnyk
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

nimek created an issue. See original summary.

PA robot’s picture

Status: Active » Needs work

There are some errors reported by automated review tools, did you already check them? See http://pareview.sh/pareview/httpsgitdrupalorgsandboxnimek2704251git

We are currently quite busy with all the project applications and we prefer projects with a review bonus. Please help reviewing and put yourself on the high priority list, then we will take a look at your project right away :-)

Also, you should get your friends, colleagues or other community members involved to review this application. Let them go through the review checklist and post a comment that sets this issue to "needs work" (they found some problems with the project) or "reviewed & tested by the community" (they found no major flaws).

I'm a robot and this is an automated message from Project Applications Scraper.

nimek’s picture

I fixed all PSR-2 errors and warnings.
To be honest a lot of Drupal modules are not 100% PSR-2 compatible.

nimek’s picture

Status: Needs work » Needs review
nimek’s picture

Issue summary: View changes
nimek’s picture

Issue summary: View changes
madan879’s picture

Hi nimek,

Some of suggestions from manual review of your module are below:

1. Please use hook_help in your .module file
2. Single line space is required between each functions.
3. In .module file, line no.173, 178,183 have "';", its separate line. Join to previous line itself
4. While cloning your module, unnecessarily "2704251" folder also coming. Inside nothing is there. So please remove or clone properly..

klausi’s picture

Status: Needs review » Needs work

manual review:
entity_unique_is_unique(): why would you use create_function() here? Why are you evaluating strings and cannot use EntityFieldQuery as usual? This looks very much like a code injection vulnerability, what if $entity->{$info['entity keys']['label']} contains something like "'); exec('rm -rf /');" or similar?

nimek’s picture

@madan
Tahnk you for review
1 Module is very simple to use and explained in Readme.txt and in module comments
2 Fixed
3 Enter in code. I don't know better way to put new line in single quotes. as comment says.
I need it to create dynamic code to EFQ to check entity uniqueness. You can use dpm($code);
to see what are the results of dynamic code creation.
4 Fixed

@klausi
Thank you for your review
Please note that by this module user has ability to decide what fields/properties should be considered in EFQ. So this code must be created dynamically.

$entity->{$info['entity keys']['label']} cant contain insecure code because $info is created by field_info function and $entity itself is validated by drupal.

Another thing properites/fields that are allowed to consider uniqueness are also taken from field_info function and are represented in form as checkboxes so drupal take care about their secure values.

So can I disagree that this module needs work?

sch4lly’s picture

Why don't you just set your EntityFieldQuery up like this:

$query = new EntityFieldQuery();
  switch ($setting) {
    case ENTITY_UNIQUE_DISABLED :
      return TRUE;
    break;  
    case ENTITY_UNIQUE_PER_ENTITY_TYPE :
      $query->entityCondition("entity_type, $entity_type);

    break;
    case ENTITY_UNIQUE_PER_ENTITY_BUNDLE :
      $query->entityCondition("entity_type", $entity_type);

      $query->entityCondition('bundle',$entity->{$info['entity keys']['bundle']})\;
    break;
  }

You can achieve the same level of "dynamicness" with this approach, without having to eval() your code.

nimek’s picture

@sch4lly

Please take a closer look at my code. Starting from line 192

 // Second part is based of defined fields/properties.
  foreach ($adv_setting as $key => $field_name) {
    if ($key === $field_name) {
      // Special part code for label.
      if ($field_name == $info['entity keys']['label']) {
        $code .= "->propertyCondition('" . $info['entity keys']['label'] . "', '" . $entity->{$info['entity keys']['label']} . "')";
      }
      // Special part code for author.
      elseif ($field_name == 'author') {
        $uid = db_select('users', 'u')->fields('u', array('uid'))->condition('name', $entity->name)->execute()->fetchField();
        $code .= "->propertyCondition('uid', '" . $uid . "')";
      }
      // Normal for other properties.
      elseif (strpos($field_name, 'field_') === FALSE) {
        $code .= "->propertyCondition('" . $field_name . "', '" . $entity->{$field_name} . "')";
      }
      // And special part for fields.
      else {
        $field_info = field_info_field($field_name);
        $target_id_label = key($field_info['columns']);
        // Foreach to support multivalue fields.
        foreach ($entity->{$field_name}[LANGUAGE_NONE] as $delta => $value) {
          if (!empty($entity->{$field_name}[LANGUAGE_NONE][$delta][$target_id_label])) {
            $code .= "->fieldCondition('" . $field_name . "', '" . $target_id_label . "','" . $entity->{$field_name}[LANGUAGE_NONE][$delta][$target_id_label] . "', '=')";
          }
        }
      }
    }
  }

I think that advanced level of dynamic code generation is note possible without eval. If you know better solution please post it here.

sch4lly’s picture

This should work just fine:

// Second part is based of defined fields/properties.
foreach ($adv_setting as $key => $field_name) {
    if ($key === $field_name) {
// Special part code for label.
        if ($field_name == $info['entity keys']['label']) {
            $query->propertyCondition($info['entity keys']['label'], $entity->{$info['entity keys']['label']});
        } // Special part code for author.
        elseif ($field_name == 'author') {
            $uid = db_select('users', 'u')->fields('u', array('uid'))->condition('name', $entity->name)->execute()->fetchField();
            $query->propertyCondition('uid', $uid );
        } // Normal for other properties.
        elseif (strpos($field_name, 'field_') === FALSE) {
            $query->propertyCondition($field_name, $entity->{$field_name});
        } // And special part for fields.
        else {
            $field_info = field_info_field($field_name);
            $target_id_label = key($field_info['columns']);
// Foreach to support multivalue fields.
            foreach ($entity->{$field_name}[LANGUAGE_NONE] as $delta => $value) {
                if (!empty($entity->{$field_name}[LANGUAGE_NONE][$delta][$target_id_label])) {
                    $query->fieldCondition($field_name, $target_id_label,$entity->{$field_name}[LANGUAGE_NONE][$delta][$target_id_label], '=');
                }
            }
        }
    }
}


sch4lly’s picture

I think you can replace

   $oryginal_entity = entity_load_single($entity_type, $entity_id);
    foreach (get_object_vars($oryginal_entity) as $key => $value) {
      $entity->{$key} = $value;
    }

with just

$entity = entity_load_single($entity_type, $entity_id);
nimek’s picture

@sh4lly
Thank you :) I commited your sugestions from #10 and #12. I forgot that i work with $query object so i can use as many methods as i want before execution.

#13 willl not work It will result with creation of new entity. I tried it earlier.

sch4lly’s picture

One more thing I noticed: your use of drupal_static in line 167 will probably result in unexpected results when saving multiple entities during one request (for example during an import), because after checking the first entity drupal_static(__FUNCTION__) will be populated with its ID, the check in line 168 will fail, the following entities won't get checked for uniqueness and the function will just return the former ID.

I have not tested this though.

I suggest either using a string like 'entity_unique_'.entity_id($entity_type, $entity) instead of __FUNCTION__ or just dropping the drupal_static altogether.

nimek’s picture

Good point. You are probably right. I will test it tomorrow and will make a fix if needed.
Can I put issue in needs review state now?

sch4lly’s picture

Status: Needs work » Needs review

Sure! Great work so far.

alex.skrypnyk’s picture

FILE: /www/2704251/entity_unique.module
----------------------------------------------------------------------
FOUND 1 ERROR AFFECTING 1 LINE
----------------------------------------------------------------------
 15 | ERROR | [x] Expected 1 blank line before function; 0 found
----------------------------------------------------------------------
PHPCBF CAN FIX THE 1 MARKED SNIFF VIOLATIONS AUTOMATICALLY
----------------------------------------------------------------------
alex.skrypnyk’s picture

Patch with spelling fixes attached.

visabhishek’s picture

@alex.designworks : Looks like you forgot to change the status. Is this now RTBC after your review or are there application blockers left and this should be "needs work"?

yogeshmpawar’s picture

Automated Review

Please check the errors in automatic reviews
http://pareview.sh/pareview/httpsgitdrupalorgsandboxnimek2704251git

Manual Review

Individual user account
Yes: Follows the guidelines for individual user accounts.
No duplication
Yes: Does not cause module duplication and/or fragmentation.
Master Branch
Yes: Follows the guidelines for master branch.
Licensing
Yes: Follows the licensing requirements.
3rd party assets/code
Yes: Follows the guidelines for 3rd party assets/code.
README.txt/README.md
No: Does not follow the guidelines for in-project documentation and/or the README Template.
Code long/complex enough for review
Yes: Follows the guidelines for project length and complexity.
Secure code
Yes: Meets the security requirements.
Coding style & Drupal API usage
[List of identified issues in no particular order. Use (*) and (+) to indicate an issue importance. Replace the text below by the issues themselves:
  1. (*) 1. As mentioned in the README.txt 'Admin > Structure > Entity type > Entity bundle' configuration page not viewable after installing the module. so please look into the issue or please update the README.txt file with proper description for how to use this module & configuration page link. you can also add configuration page link in .info file
  2. (+) 1. It would be good, if you implement hook_help & hook_permission in your module.
  3. Just a recommendation - Nothing

The starred items (*) are fairly big issues and warrant going back to Needs Work. Items marked with a plus sign (+) are important and should be addressed before a stable project release. The rest of the comments in the code walkthrough are recommendations.

If added, please don't remove the security tag, we keep that for statistics and to show examples of security problems.

This review uses the Project Application Review Template.

nimek’s picture

@alex.designworks thanks for a patch. It is added and all errors are fixed.

@Yogesh Pawar
README.txt fixed
hook_permission is not needed I use administer site configuration similar like for example Automatic Entity Labels module
hook_help - it is very simple module to use. Really every module needs that?

Thank you for your time guys :-)

visabhishek’s picture

Status: Needs review » Reviewed & tested by the community

Module looks good and working fine for me. I think we don't have any blocker, So I am marking as RTBC.

@nimek :

1: Please fix the spelling mistake in .info file.
uniqness => uniqueness
2: Please fix online review points : http://pareview.sh/pareview/httpgitdrupalorgsandboxnimek2704251git
3: Its good to have hook_help (All but the most trivial modules should implement hook_help().)

nimek’s picture

@visabhishek thank you for your time :)

1 and 2 fixed

3 I added hook_help.

Are there still any release blockers?

MiSc’s picture

Looks good I think, so:

Thanks for your contribution, nimek!

I updated your account so you can promote this to a full project and also create new projects as either a sandbox or a "full" project.

Here are some recommended readings to help with excellent maintainership:

You can find lots more contributors chatting on IRC in #drupal-contribute. So, come hang out and stay involved!

Thanks, also, for your patience with the review process. Anyone is welcome to participate in the review process. Please consider reviewing other projects that are pending review. I encourage you to learn more about that process and join the group of reviewers.

Thanks to the dedicated reviewer(s) as well.

MiSc’s picture

Status: Reviewed & tested by the community » Fixed

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.