We just spent about an hour dissing poll module in irc, and amateescu volunteered to help maintain it (either in core or contrib).

To make it more maintainable, it would be good to modernize it to use a field type - this could potentially be the D7 port of http://drupal.org/project/pollfield.

things to do:

Create a field type with widget and formatter that replicates what poll does now.

Nuke the hook_node_type() implementation and any other references to node module, will need an upgrade path to create a 'poll' node type with a field instance for existing poills.

The Field API integration may be tricky (i.e. you'd need a formatter that includes the voting form, as well as potentially showing results).

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

amateescu’s picture

I'd like to see a debate here about the things that should/can be done to keep Poll in D8 core.

Once an agreement is reached, as I said in IRC, I would like to offer my services in implementing and maintaing it :)

sun’s picture

Thanks, this gives some hope about Poll module.

What @catch outlined is pretty much everything that would have to be done. In the end, it is going to be a field type module like all the other field type modules (text, number, file, image, etc).

The only kind of "debate" we could have here would be whether it makes sense to keep poll as a monolithic module/field, or whether it wouldn't make much more sense to replace it entirely with @fubhy's Vote module, which attempts to be a generic replacement for Poll, Voting API, Fivestar, and Flag - so we'd have a major building block module in core instead of a single-purpose implementation. But that said, I'm not sure how much progress @fubhy was able to do on the architectural side and development yet (I only know he had many discussions with @eaton), so Vote module might not be an option yet.

fubhy’s picture

sub

jessebeach’s picture

sub

fubhy’s picture

I talked to amateescu about this in IRC yesterday.

Let me explain the Vote module based on the example of a "Restaurant Evaluation" real quick.

So, what the Vote module does is, it stores a vote with a certain integer value, a criterion (e.g. "Service", "Taste", "Look" of a meal), a reference to a target entity and the reference to the user id of the user who cast the vote. There are multiple possible value types that a vote can have, like "Percent" or "Point". In this case it would be a "Choice" vote where the integer value of a vote would represent the key of one of the available options.

The "criterion" always references a configuration element which extends the plain machine-readable name of that criterion with a label, information about the value type, about which values it accepts (in case of a "choice" vote this would be only the keys of the options that are available, in case of a "percent" vote this would be 0 to 100, etc.) and which result functions are associated with it. So in addition to what VotingAPI did with this we are going to explicitly define "criterions" and attach information and configuration to them.

Vote results are stored as seperate entities and represent the cached result values of a result function that has been invoked on a certain criterion for a certain target entity. Possible result functions are "average", "sum" or "count". It is necessary to cache those values are a website that hosts millions of votes would have severe performance problems while trying to calculate such values with database expressions on a per-page-view basis.

So... Value types are simple representations of a controller class that handle the way a vote is treated and result functions are simple callbacks that populate a VoteResult entity with a result value. Those two are defined in code and are completely pluggable.

So if we save a new vote with the value "10" on "Service" for the node (restaurant) "McDonald's" ("Service" being a 1-100 [percent] vote) we look up the configuration for the criterion "Service", then validate the value of the vote by forwarding it through the value type controller. Then we look up all result functions that are associated with that criterion and either invoke them directly or queue them for recalculation via hook_cron_queue_info based on the settings of the criterion.

An implementation for the Poll module could look like this: The Poll module would provide a field type which would use the Field Settings UI to expose a form for configuring the settings for the criterion. The bad thing about this approach is that the field would really just serve as a way to attach the poll to an entity and configure it on the Field UI but it would not store any data.

As I see it the Poll module should really just be this: A independent Field Type that uses the delta's of a Field to provide the different options and then stores the count of each of those delta's in the Field delta's aswell (so we have two columns in the field schema: 1) option 2) count). Every time a user clicks on one of the options in the frontend we would increment the count by 1 or reduce it by 1. Done. For me this sounds much too simple and does not really legitimate the use of the Vote module.

Thoughts?

fubhy’s picture

Note: I am not saying that it is not possible. The field could possibly act as a pool for the Vote and the VoteResult entities and that would allow us to do some cool juggling with the data. I am just not sure wether such a simple thing (which a Poll basically is) should be based on Vote or not.

giorgio79’s picture

Re #5 "As I see it the Poll module should really just be this: A independent Field Type that uses the delta's of a Field to provide the different options and then stores the count of each of those delta's in the Field delta's aswell (so we have two columns in the field schema: 1) option 2) count). Every time a user clicks on one of the options in the frontend we would increment the count by 1 or reduce it by 1. Done. For me this sounds much too simple and does not really legitimate the use of the Vote module."

Yes, as I understand this is how pollfield works, it creates a separate column for each voting option in the content type table, and saves the votes. Pollfield does not yet have a D7 port, so that is maybe a good place to start instead of D8, and see how it progresses in contrib so it can be ready for core in D8:
#1074958: Pollfield: D7 port?

I also notice that http://drupal.org/project/advpoll uses Voting API, maybe some ideas can be taken from there, but just like the core Poll it is not integrated as a CCK / Field.

earthday47’s picture

I'm willing to offer code to make this happen. I'm also very interested in a contrib module that works with D7 today.

I think these two definitions of polls are too exteme. We've got the uber-simple: Select an option and increment by one. We've got the uber-complex: Fold in Voting API, etc.

This is what I strongly think a Poll module should be, focused and use-case oriented. Core Poll (mostly) does this.

  • A question and multiple answers
  • Select one (radios) or select multiple (checkboxes) *core Poll module doesn't do this, serious limitation*
  • Vote by user, or vote anonymously, with IP, session, or cookie for anonymous
  • Display results as a percentage bar

Wordpress' WP-Polls plugin is excellent, and we should draw a lot of inspiration from it.

Let me know how else I can help.

Michelle’s picture

As I'm going to need some sort of poll field for Artesian, I'm interested in this discussion. I don't think poll and voting modules are really the same thing. All the voting modules are really aimed at putting some sort of rating on an entity. Poll/pollfield is about rating a question that is on an entity. That's different enough that I think it would be difficult to try to make a rating module into a poll and also likely overkill.

Michelle

andypost’s picture

Do this issue depends on #1785256: Widgets as Plugins #1785748: Field formatters as plugins or not?
Probably it could be converted latter to new plugins

jcisio’s picture

Assigned: Unassigned » jcisio

I'll try to work on this in the next few days.

andypost’s picture

@jcisio please explain what you think about storage/ui/implementation you are trying to introduce?

I see a poll as config entity (define a bundle) with votes attached on a top of pluggable storage like #1825044: Turn contact form submissions into full-blown Contact Message entities, without storage does. The only questionable part is a field implementation that should be a kind of #1801304: Add Entity reference field but this does not support a reference to config entity

sun’s picture

Title: Make a poll field type » Modernize Poll module
Assigned: jcisio » Unassigned
Issue tags: +Platform Initiative

I looked a bit into this and studied what the current Poll module is doing, what the contrib pollfield module is doing, and what the OP and comments in this issue are suggesting.

My train of thought starts from a user perspective:

As an end-user of a site, I want to create a poll that others can vote on.

Note: "end-user" does not necessarily mean site administrator/site builder.

That's a super simple user story, but with the approaches being suggested here, I'd have no idea how an end-user could do that, without granting all of your users the permissions to Manage fields. ;)

What this essentially entails is one of the following options:

  1. There's a separate entity that represents a poll, denoting its title, options/schema, and voting settings. This entity is essentially referenced from a poll field instance value, whereas the field [value] is really just an entity reference field.

    Due to the entity reference, a poll can be re-used and shown in multiple places. New polls can be created ad-hoc from within the field.

    The poll entity type essentially has two view modes: one for the voting form, and one for the voting results. It's render controller determines which of both view modes needs to be used. All poll entities can be listed independently.

  2. There's a Poll field. The field instance has no settings. The field widget allows to specify the field's label, the poll options/schema, and voting settings. These values (i.e., the poll settings) are saved as field values. The field formatter renders a corresponding voting form for the poll. The voting form essentially leads to vote records that are stored elsewhere, outside of the field. The field formatter contains additionally required logic to switch between the voting form and the vote results, in case a user has voted already.

    Polls should allow to view the voting results without requiring to vote, so there'd have to be a request query parameter that indicates to render the voting results instead of the voting form. In general, the voting form vs. voting results field formatting presents a challenge, since rendered fields are cached (AFAIK), and submitting a vote does not change or update the entity containing the poll field in any way.

    The second best challenge with this design is that there should be an archive (page) of recent polls, but the only place where polls are stored are in poll field values, and D8's new EntityFieldQuery does not allow to retrieve all fields of a certain type across entity types anymore.

    [...]

The more I think about this, the more I conclude that option 2) only appears to be simpler on the surface, but involves massive challenges down the line.

Therefore, I'm inclined to recommend option 1), which would essentially mean that the "field" part would actually be covered by #1801304: Add Entity reference field already, and what we'd rather do here is to convert the poll node/content type (bundle) into a poll entity type. (Which makes sense, because a poll is not really "content" in the sense of an authored article, but much rather an entity that has its own business logic and which is commonly displayed in a block and so on.)

What do you think?

(Tentatively adjusting the issue title based on this analysis — I don't think it makes sense to force-stick on the idea of a poll field; the underlying primary goal should much rather be that Poll module becomes a modern, cool, and fun thing to work with, so it deserves and retains its place in Drupal core and we can advance on it for D9.)

jcisio’s picture

I spent a few hours the last days to try Poll/Pollfield and had the same two approaches.

- Poll Field: poll as field allows it to be easily attached to any entity, have different rendering in different view modes. However, as a poll has multiple choices, we end up with store the choices either in a serialized column or in a separate table (then "choices" à-la-field).

- Poll Entity: the poll field becomes an entity reference field and the poll itself becomes a poll entity (like Field Collection module), choices become simple a text field. The tricky bit is the creation of poll entity inside the node (or entity, but it is out of scope) form, and everything becomes a little more complex. The idea could be turn the poll node in D5/D6 to D8 poll entity, allow to create poll entity independant to node. It might hurt the UX, at least if we can't use the poll entity as a stand-alone entity. Then we finally "invent" a poll entity that looks like exactly a poll node (well, a bit lighter).

Let's go back to the questions raisen in #13.

- Poll listing page for Poll field: even we can do a single EFQ to get all polls, we can do multiple EFQ. I don't think the poll listing page is something that needs optimization.

- Render the result in the same entity view mode: the problem still exists if we replace the poll field with poll entity reference field.

I don't think neither poll field nor poll entity is better. Maybe we need to figure out the most important use cases of Poll to get a response.

NaheemSays’s picture

When i use the poll, features I am interested in that are not currently present are:

1. It can be added to multiple nodes (but so can fields...)
2. Many softwares allow polls to be created at different times from the main content (node in this case). This can also be done with a field but seems cleaner as an entity.
(3. Different voting types.)

A use case is creating a forum topic and then later adding a poll to it. It can be done with both as a field and as an entity, but having it as an entity seems cleaner to me from the end user point of view, but there would also be a need to be able to go from the poll to the node that it is linked to for the discussions on the topic.

alexpott’s picture

Project: Drupal core » Poll
Version: 8.x-dev » 8.x-1.x-dev
Component: poll.module » Code

Moving task to the new Poll (from core) module

klonos’s picture

Despite the fact that the Pollfield module seems to be abandoned/neglected, there's some people still pushing for things to happen: #1345600: Pollfield 7.x-2.x-dev with support for EntityFieldQuery and bug fixes. Perhaps they'd be interested to volunteer to help here too. Or perhaps work done here synced to that project as a D7 backport.

dakala’s picture

Assigned: Unassigned » dakala

I'd like to start the ball rolling along the line of option 1, #13: https://drupal.org/node/1266336#comment-6823308. I'm volunteering unless someone else is interested.

dakala’s picture

Follow my work on Poll (from core) here: https://github.com/dakala/poll. I've been in touch with @typhonius and we'll be co-ordinating effort on this. Leave comments here or on github, please.

klonos’s picture

These are great news Deji! Thank you for taking the time to update us on the status and do keep updating. Lets us know what you perhaps need to test.

dakala’s picture

@klonos: Thanks. I've been in touch with typhonius who's the maintainer of this module and we'll be coming up with a common strategy soon. At the moment, the work I'm doing is on poll as an entity with poll choice fields. It's the middle ground between the old poll and pollfield modules. This looks like the right way to go but it all depends on what people think when they start playing with the new poll module.

Currently, polls can be created and updated. There's also a list view of available polls. The next step is to display the voting form which I hope to complete in the next few days.

andypost’s picture

poll as an entity with poll choice fields

Please elaborate on approach. Using entity to store metadata information (settings for poll) is not a good idea - you limit the number of settings with base fields.
Also it would be great to have some kind of cache for poll stats (to not query averages each time)
Suppose better to follow the poll field way as we done for comments.

dakala’s picture

Currently these are the basefield definitions:


public static function baseFieldDefinitions($entity_type) {
    $properties['id'] = array(
      'label' => t('Poll ID'),
      'description' => t('The poll ID.'),
      'type' => 'integer_field',
      'read-only' => TRUE,
    );
    $properties['uid'] = array(
      'label' => t('User ID'),
      'description' => t('The user ID of the poll author.'),
      'type' => 'entity_reference_field',
      'settings' => array(
        'target_type' => 'user',
        'default_value' => 0,
      ),
    );
    $properties['uuid'] = array(
      'label' => t('UUID'),
      'description' => t('The poll UUID.'),
      'type' => 'uuid_field',
      'read-only' => TRUE,
    );
    $properties['question'] = array(
      'label' => t('Question'),
      'description' => t('The poll question.'),
      'type' => 'string_field',
      'required' => TRUE,
      'settings' => array(
        'default_value' => '',
      ),
    );
    $properties['langcode'] = array(
      'label' => t('Language code'),
      'description' => t('The poll language code.'),
      'type' => 'language_field',
    );
    $properties['anonymous_vote_allow'] = array(
      'label' => t('Anonymous votes allowed'),
      'description' => t('A boolean indicating whether anonymous users are allowed to vote.'),
      'type' => 'boolean_field',
    );
    $properties['cancel_vote_allow'] = array(
      'label' => t('Cancel votes allowed'),
      'description' => t('A boolean indicating whether users may cancel their vote.'),
      'type' => 'boolean_field',
    );
    $properties['result_vote_allow'] = array(
      'label' => t('View results allowed'),
      'description' => t('A boolean indicating whether users may see the results before voting.'),
      'type' => 'boolean_field',
    );
    $properties['runtime'] = array(
      'label' => t('Runtime'),
      'description' => t('The number of seconds after creation during which the poll is active'),
      'type' => 'integer_field',
    );
    $properties['status'] = array(
      'label' => t('Status'),
      'description' => t('A boolean indicating whether the poll is active.'),
      'type' => 'boolean_field',
    );
    $properties['created'] = array(
      'label' => t('Created'),
      'description' => t('The time that the poll was created.'),
      'type' => 'integer_field',
      'settings' => array(
        'default_value' => '0',
      ),
    );

    return $properties;
  }

  

The poll choice field (similar to pollfield and link in core) holds Choice and Votes values for each poll option:


public static function schema(FieldInterface $field) {
    return array(
      'columns' => array(
        'choice' => array(
          'type' => 'varchar',
          'length' => 255,
          'not null' => FALSE,
        ),
        'vote' => array(
          'type' => 'int',
          'unsigned' => TRUE,
          'not null' => FALSE,
        ),
      ),
      'indexes' => array(
        'choice' => array('choice'),
        'vote' => array('vote'),
      ),
    );
  }

It's very much work in progress and we would most certainly appreciate any input.

dakala’s picture

Issue summary: View changes
FileSize
39.38 KB

Hi All,

I've updated the poll module here: https://github.com/dakala/poll Will try to follow updates to core to make the module work. Attached is the latest copy. Have a play and any feedback is welcome!

adammalone’s picture

Issue tags: +DrupalSouth

tagging for the sprint weekend to incorporate dakala's changes and bring poll up to speed with latest 8.x

dakala’s picture

@typhonius: That's great. I might be able to drop in during the sprint if I know the date and time. Thanks.

dakala’s picture

FileSize
71.75 KB

@All: Attached is my latest code updated for D8-alpha11. The choice field is now a module on its own to make it easier to uninstall poll module itself. Feedback, anyone?

Here's the github url: https://github.com/dakala/poll

adammalone’s picture

@dakala I'm wondering if it might be an idea to create the choice field as a field of the poll module rather than its own separate module? I suppose the concern around uninstalling the poll module would be alleviated if poll module alone made use of the choice field.

dakala’s picture

@typhonius: Sure it can be moved back into the poll module itself (that's where it's been until last week). I guess the problem of uninstallation will be resolved later. In core, comment module implements a commentfield which makes comment module unavailable for uninstallation. Then we have block and custom_block modules with custom_block a separate module inside the block directory - both are available for uninstallation.

If the choice field is implemented in the poll module itself, we can't uninstall the poll module. Are we okay then with having the choice field implemented in the poll module and not to be able to uninstall the module?

adammalone’s picture

@dakala, I just had a play around with comment module and as long as the fields themselves are manually deleted, the comment module is able to be uninstalled also.

With the way uninstallation works in D8 (all module data gets trashed), I figure that anyone wishing to uninstall poll will also want all their poll entities trashed too. If users want to get rid of poll, I suppose they can remove the poll choice field and then delete the poll module itself... Thoughts?

dakala’s picture

@typhonius: Ah, yes. I get what you mean. I'll move the choice field back into the poll module.

dakala’s picture

FileSize
30.19 KB

The choice field has now been moved back into poll module. Latest code from https://github.com/dakala/poll is attached.

Berdir’s picture

Status: Active » Fixed

Marking this as fixed. This has been merged long ago and improved upon.

Status: Fixed » Closed (fixed)

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