### List Polls Example Request Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/ApiResources.md Example of a GET request to list polls, demonstrating sorting, pagination, and including related data. ```http GET /api/polls?sort=-createdAt&page[limit]=20&include=options,myVotes ``` -------------------------------- ### CreatePollGroup Command Example Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/Commands.md Example of creating and dispatching a CreatePollGroup command. ```php $command = new CreatePollGroup( actor: $user, data: [ 'attributes' => [ 'name' => 'Feature Requests' ] ] ); $group = $bus->dispatch($command); ``` -------------------------------- ### PublishPoll Command Examples Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/Commands.md Examples of creating a PublishPoll command for immediate or scheduled publication. ```php // Publish immediately $command = new PublishPoll( pollId: 5, actor: $user, data: ['attributes' => []] ); // Publish at scheduled time $command = new PublishPoll( pollId: 5, actor: $user, data: [ 'attributes' => [ 'scheduledFor' => '2026-06-15T10:00:00Z' ] ] ); $poll = $bus->dispatch($command); ``` -------------------------------- ### UnpublishPoll Command Example Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/Commands.md Example of creating and dispatching an UnpublishPoll command. ```php $command = new UnpublishPoll( pollId: 5, actor: $user, data: [] ); $poll = $bus->dispatch($command); ``` -------------------------------- ### List All Poll Groups with Polls and User Info Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/PollGroup.md Example of listing all poll groups, including their associated polls and creator information, using a GET request to the /api/poll_groups endpoint with include parameters. ```bash curl /api/poll_groups?include=polls,user ``` -------------------------------- ### Dispatching Commands via Bus Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/Commands.md Example of resolving the command bus and dispatching a command. ```php use Flarum\Bus\Dispatcher; $bus = resolve(Dispatcher::class); $poll = $bus->dispatch(new CreatePoll(...)); ``` -------------------------------- ### Install Polls Extension Source: https://github.com/friendsofflarum/polls/blob/2.x/README.md Use this Composer command to install the latest version of the fof/polls extension. ```sh composer require fof/polls:"*" ``` -------------------------------- ### Search Filter Example Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/types.md Demonstrates how to use query parameters to filter polls by their ended status and draft status. ```http GET /api/polls?filter[isEnded]=no&filter[isDraft]=no ``` -------------------------------- ### Example Search Query with Filters Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/Events.md Demonstrates how to use the filter method on a repository to query polls based on criteria like 'isEnded', 'isDraft', and 'isHidden'. ```php $polls = $repository->queryVisibleTo($actor) ->filter('isEnded', 'yes') ->filter('isDraft', 'no') ->get(); ``` -------------------------------- ### Get a Specific Poll Group with Detailed Polls Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/PollGroup.md Example of retrieving a single poll group by ID, including its polls, poll options, and creator information, using a GET request to /api/poll_groups/{id} with specific include parameters. ```bash curl /api/poll_groups/2?include=polls,polls.options,user ``` -------------------------------- ### ToMany Relationship Example Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/types.md Illustrates a 'ToMany' relationship structure, showing how multiple related resources (e.g., poll options) are represented. ```json { "relationships": { "options": { "data": [ {"type": "poll_options", "id": "1"}, {"type": "poll_options", "id": "2"}, {"type": "poll_options", "id": "3"} ] } } } ``` -------------------------------- ### Registering Event Listeners Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/Events.md Shows how to register event listeners in the extend.php file using the Extend\\\Event class. Includes examples for named listeners, class-based listeners, and inline closure listeners. ```php (new Extend\Event()) ->listen(PollWasCreated::class, MyPollCreatedListener::class) ->listen(PollImageWillBeResized::class, MyImageValidator::class) ->listen(PollWasVoted::class, function (PollWasVoted $event) { // Inline closure listener Log::info('Voted: ' . $event->actor->username); }) ``` -------------------------------- ### API Resource Scope example Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/PollRepository.md Demonstrates how to apply the visibility scope within an API resource's scope method to filter queries based on the actor's visibility. ```php public function scope(Builder $query, OriginalContext $context): void { $query->whereVisibleTo($context->getActor()); } ``` -------------------------------- ### PollImageWillBeResized Listener Example Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/Events.md An example listener for the PollImageWillBeResized event. This listener validates image dimensions, throwing a ValidationException if the image is too small. ```php use FoF\Polls\Events\PollImageWillBeResized; class ValidateImageDimensions { public function handle(PollImageWillBeResized $event) { if ($event->image->width() < $event->baseWidth / 2) { throw new ValidationException([ 'pollImage' => 'Image is too small' ]); } } } ``` -------------------------------- ### SavingPollAttributes Listener Example Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/Events.md An example listener for the SavingPollAttributes event. This listener customizes poll behavior based on provided attributes, such as hiding votes if 'isSpam' is true. ```php public function handle(SavingPollAttributes $event) { // Customize poll based on attributes if ($event->attributes['isSpam'] ?? false) { $event->poll->hide_votes = true; } } ``` -------------------------------- ### Forum Resource Attributes Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/endpoints.md Example of the JSON response when fetching forum resource details. Includes flags for poll-related features. ```JSON { "data": { "type": "forums", "id": "1", "attributes": { "canStartGlobalPolls": true, "canUploadPollImages": true, "canStartPollGroup": false, "canViewPollGroups": false, "discussionPollsEnabled": true, "globalPollsEnabled": true, "pollGroupsEnabled": false, "pollMaxOptions": 10 } } } ``` -------------------------------- ### Command Handler for Poll Analysis Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/PollRepository.md Example of a command handler that uses PollRepository to fetch a specific poll and its related data, including options and status. ```php class AnalyzePollCommand { public function __construct(protected PollRepository $repository) {} public function handle($pollId, User $actor) { $poll = $this->repository->findOrFail($pollId, $actor); if (!$poll) { throw new ModelNotFoundException(); } return [ 'poll' => $poll, 'options' => $poll->options, 'voteCount' => $poll->vote_count, 'hasEnded' => $poll->hasEnded(), ]; } } ``` -------------------------------- ### Accessing Poll Settings Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/types.md Demonstrates how to retrieve and access poll settings, both as a JSON array and through model accessors. This example assumes a 'Poll' model instance is already found. ```php $poll = Poll::find(1); $settings = $poll->settings; // Access as array if ($settings['public_poll']) { echo "Votes are public"; } // Or via accessors if ($poll->public_poll) { echo "Votes are public"; } ``` -------------------------------- ### ToOne Relationship Example Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/types.md Shows a 'ToOne' relationship structure, representing a single related resource (e.g., a user associated with a poll). ```json { "relationships": { "user": { "data": {"type": "users", "id": "42"} } } } ``` -------------------------------- ### Query Polls with Filters and Sorting Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/QuickStart.md Fetch a list of polls with applied filters and sorting. This example filters for non-ended polls, sorts them by vote count in descending order, and limits the results to 20 per page. ```bash curl /api/polls?filter[isEnded]=no&sort=-voteCount&page[limit]=20 ``` -------------------------------- ### Listen to Poll Creation Event Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/Events.md Example of how to register a listener for the PollWasCreated event in your extend.php file. This listener logs the poll question and the username of the creator. ```php use FoF\Polls\Events\PollWasCreated; use Illuminate\Contracts\Events\Dispatcher; class LogPollCreation { public function handle(PollWasCreated $event) { Log::info('Poll created: ' . $event->poll->question . ' by ' . $event->actor->username); } } // Register in extend.php (new Extend\Event()) ->listen(PollWasCreated::class, LogPollCreation::class) ``` -------------------------------- ### Handle Poll Vote Event Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/Events.md Example of how to handle the PollWasVoted event. This listener logs the username of the voter, the poll ID, and the number of options they voted for. ```php public function handle(PollWasVoted $event) { // $event->votedOptions contains [8, 9] if user voted for those $count = count($event->votedOptions); Log::info("{$event->actor->username} voted on poll {$event->poll->id} ({$count} options)"); } ``` -------------------------------- ### Get all polls (unfiltered) Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/PollRepository.md Use the query() method to get a base query builder for all polls without any visibility filtering. This is useful for administrative tasks or when you need to access all poll data. ```php $repository = resolve(PollRepository::class); // Get all polls (unfiltered) $allPolls = $repository->query()->get(); ``` -------------------------------- ### Null Relationship Example Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/types.md Demonstrates how a null relationship is represented when a resource is not linked to another (e.g., a global poll without an associated post). ```json { "relationships": { "post": { "data": null } } } ``` -------------------------------- ### Get Responsive Image Sizes Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/PollImageUploader.md Computes and returns the responsive image dimensions (width, height) based on admin settings for the base image and its HiDPI variants (@2x, @3x). ```APIDOC ## getSizes() ### Description Computes the responsive image dimensions from admin settings. ### Method `public function getSizes(): array` ### Parameters None ### Request Example ```php $sizes = $uploader->getSizes(); foreach ($sizes as $suffix => [$width, $height]) { echo "$suffix: {$width}x{$height}\n"; } ``` ### Response #### Success Response (200) - **array** - An associative array where keys are suffixes (e.g., "", "@2x", "@3x") and values are arrays containing [width, height]. #### Response Example ```json { "": [250, 250], "@2x": [500, 500], "@3x": [750, 750] } ``` ``` -------------------------------- ### Configuring Poll Image Disk Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/configuration.md Set up a dedicated filesystem disk for storing poll images using Flarum's Extend API. This example shows how to define the 'fof-polls' disk using a custom class. ```php (new Extend\Filesystem()) ->disk('fof-polls', PollImageDisk::class) ``` -------------------------------- ### Create a Poll Group via API Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/PollGroup.md Example of creating a new poll group using a POST request to the /api/poll_groups endpoint. Requires authentication and appropriate permissions. ```bash curl -X POST /api/poll_groups \ -H "Authorization: Bearer {token}" \ -d '{ \ "data": { \ "type": "poll_groups", \ "attributes": { \ "name": "Feature Requests" \ } \ } \ }' ``` -------------------------------- ### Permission Denied Error Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/errors.md This error occurs when a user attempts an action without the necessary permissions, such as starting a poll. ```json { "errors": [ { "status": 403, "code": "permission_denied", "detail": "You do not have permission to start a poll." } ] } ``` -------------------------------- ### Post Resource Attributes with Polls Relationship Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/endpoints.md Example of a post resource when discussion polls are enabled. Includes a 'polls' relationship if the post has polls. ```JSON { "data": { "type": "posts", "id": "5", "attributes": { "canStartPoll": true }, "relationships": { "polls": { "data": [ {"type": "polls", "id": "1"} ] } } } } ``` -------------------------------- ### Discussion Resource Attributes Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/endpoints.md Example of attributes included in a discussion resource when discussion polls are enabled. Shows poll status and permissions. ```JSON { "data": { "type": "discussions", "id": "1", "attributes": { "hasPoll": true, "canStartPoll": false, "title": "..." }, "relationships": { "firstPost": { "data": {"type": "posts", "id": "5"} } } } } ``` -------------------------------- ### Get Responsive Image Sizes Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/PollImageUploader.md Computes the responsive image dimensions based on admin settings. This method returns an array defining the sizes for base (1x), 2x, and 3x variants. ```php $sizes = $uploader->getSizes(); foreach ($sizes as $suffix => [$width, $height]) { echo "$suffix: {$width}x{$height}\n"; } ``` -------------------------------- ### Configure Cron Job for Scheduled Polls Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/configuration.md Set up a cron job to automatically run the Flarum scheduler, which includes publishing scheduled polls. Ensure the path to your Flarum installation is correct. ```bash * * * * * cd /path/to/flarum && php flarum schedule:run >> /dev/null 2>&1 ``` -------------------------------- ### Poll Analytics Service Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/PollRepository.md An example of a service class that uses PollRepository to fetch poll data for analytics purposes, including most voted polls and user-specific stats. ```php class MyPollAnalytics { public function __construct( protected PollRepository $repository, protected SettingsRepositoryInterface $settings ) {} public function getMostVotedPolls($limit = 5) { return $this->repository->query() ->where('published_at', '!=', null) ->orderBy('vote_count', 'desc') ->limit($limit) ->get(); } public function getUserPollStats($user) { $polls = $this->repository->query() ->where('user_id', $user->id) ->get(); return [ 'total' => $polls->count(), 'global' => $polls->where('post_id', null)->count(), 'discussion' => $polls->where('post_id', '!=', null)->count(), 'totalVotes' => $polls->sum('vote_count'), ]; } } ``` -------------------------------- ### Create a Poll within a Specific Group via API Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/PollGroup.md Example of creating a new poll and assigning it to an existing poll group using a POST request to the /api/polls endpoint, specifying the poll group in the relationships. ```bash curl -X POST /api/polls \ -H "Authorization: Bearer {token}" \ -d '{ \ "data": { \ "type": "polls", \ "attributes": { \ "question": "Should we implement X?", \ "publicPoll": true, \ "options": [ \ {"answer": "Yes"}, \ {"answer": "No"}, \ {"answer": "Maybe"} \ ] \ }, \ "relationships": { \ "pollGroup": { \ "data": {"type": "poll_groups", "id": "2"} \ } \ } \ } \ }' ``` -------------------------------- ### Get Poll API Endpoint Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/README.md Use this GET endpoint to retrieve a specific poll by its ID. Refer to the API reference for response structure. ```http GET /api/polls/{id} Get poll ``` -------------------------------- ### Basic Error Handling in a Listener Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/Events.md Illustrates a best practice for handling exceptions within a listener to prevent critical failures and log errors gracefully. Avoids re-throwing unless absolutely necessary. ```php public function handle(PollWasCreated $event) { try { // Do something } catch (Exception $e) { Log::error('Listener failed: ' . $e->getMessage()); // Don't re-throw unless critical } } ``` -------------------------------- ### GET /api/poll_groups Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/ApiResources.md Retrieves a list of all poll groups. Supports pagination and sorting. ```APIDOC ## GET /api/poll_groups ### Description List all poll groups. ### Method GET ### Endpoint /api/poll_groups ### Parameters #### Query Parameters - **page[offset]** (integer) - Optional - Offset for pagination. - **page[limit]** (integer) - Optional - Limit for pagination. - **sort** (string) - Optional - Sort by `createdAt`. - **include** (string) - Optional - Related data to include. ### Response #### Success Response (200 OK) - **data** (array) - An array of poll group objects. - **included** (array) - Included related data, defaults to `polls`. #### Response Example (Response body for 200 OK would typically be an array of poll group objects) ``` -------------------------------- ### Accessing Settings in PHP Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/configuration.md Retrieve configuration settings from Flarum's settings repository in PHP. Use type casting for boolean and integer settings, and provide default values. ```php use Flarum\Settings\SettingsRepositoryInterface; $settings = resolve(SettingsRepositoryInterface::class); // Get a setting with optional default $maxOptions = (int) $settings->get('fof-polls.maxOptions', 10); $globalPollsEnabled = (bool) $settings->get('fof-polls.enableGlobalPolls', false); $imageWidth = (int) ($settings->get('fof-polls.image_width') ?: 250); // Check a boolean setting if ($settings->get('fof-polls.enableDiscussionPolls', true)) { // Discussion polls are enabled } ``` -------------------------------- ### Convert Existing Images to WebP Source: https://github.com/friendsofflarum/polls/blob/2.x/README.md Use this command to convert existing PNG images to the WebP format with srcset variants. Add the --cleanup flag to remove original PNG files after successful conversion. ```sh php flarum fof:polls:convert-images ``` ```sh php flarum fof:polls:convert-images --cleanup ``` -------------------------------- ### GET /api/poll_groups/{id} Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/ApiResources.md Retrieves a single poll group by its ID, including related polls and their options/votes. ```APIDOC ## GET /api/poll_groups/{id} ### Description Get a single poll group. ### Method GET ### Endpoint /api/poll_groups/{id} ### Parameters #### Path Parameters - **id** (integer) - Required - The ID of the poll group to retrieve. ### Response #### Success Response (200 OK) - **data** (object) - The requested poll group object. - **included** (array) - Included related data: `polls`, `polls.options`, `polls.myVotes`, `polls.myVotes.option`. #### Response Example (Response body for 200 OK would typically be a single poll group object with included related data) ``` -------------------------------- ### Get Image URL Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/PollImageUploader.md Returns the public URL for a stored image file based on its base filename. ```APIDOC ## url() ### Description Returns the public URL for a stored image file. ### Method `public function url(string $basePath): string` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **basePath** (string) - Required - Base filename ### Request Example ```php $url = $uploader->url('pollImage-xY7kQ2pL.webp'); // Returns: "https://example.com/storage/poll-images/pollImage-xY7kQ2pL.webp" ``` ### Response #### Success Response (200) - **string** - Absolute public URL #### Response Example ```json "https://example.com/storage/poll-images/pollImage-xY7kQ2pL.webp" ``` ``` -------------------------------- ### Dispatching Custom Events from a Listener Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/Events.md Shows how to inject the Event Dispatcher and dispatch a custom event within a listener's handle method. ```php use Illuminate\Contracts\Events\Dispatcher; class MyListener { public function __construct(protected Dispatcher $dispatcher) {} public function handle(PollWasCreated $event) { // Dispatch custom event $this->dispatcher->dispatch(new CustomEvent($event->poll)); } } ``` -------------------------------- ### Get Poll Group Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/endpoints.md Retrieves a single poll group by its ID. Includes related poll data by default. ```HTTP GET /api/poll_groups/{id} ``` -------------------------------- ### Build a new PollOption instance Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/PollOption.md Use the static `build` method to create a new PollOption instance without saving it to the database. You can provide the answer text and an optional image URL. The created instance can then be saved as part of a poll. ```php use FoF\Polls\PollOption; $option = PollOption::build( answer: 'React', imageUrl: 'pollOptionImage-abc123.webp' ); $poll->options()->save($option); ``` -------------------------------- ### Multiple Field Validation Errors Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/types.md Example of Flarum's validation error structure when multiple fields fail validation. ```json { "errors": [ { "status": 400, "detail": "The question field is required.", "source": {"pointer": "/data/attributes/question"} }, { "status": 400, "detail": "The options field must contain at least 2 items.", "source": {"pointer": "/data/attributes/options"} } ] } ``` -------------------------------- ### GET /api/polls Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/ApiResources.md List all polls with filtering, sorting, and pagination capabilities. Allows including related data such as options and votes. ```APIDOC ## GET /api/polls ### Description List all polls with filtering, sorting, and pagination capabilities. Allows including related data such as options and votes. ### Method GET ### Endpoint /api/polls ### Parameters #### Query Parameters - **filter[*]?** (string) - Optional - Search filters. - **sort** (string) - Optional - Sort by `createdAt` or `voteCount` (prefix with `-` for descending). - **page[offset]** (integer) - Optional - Offset for pagination. - **page[limit]** (integer) - Optional - Limit for pagination. - **include** (string) - Optional - Related data to include (e.g., `options`, `myVotes`). ### Request Example ``` GET /api/polls?sort=-createdAt&page[limit]=20&include=options,myVotes ``` ### Response #### Success Response (200 OK) - **array of polls** (array) - A list of poll objects. ``` -------------------------------- ### Get User Who Created the Group Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/PollGroup.md Retrieves the user who created the poll group. Useful for displaying group ownership or for moderation. ```php $creator = $group->user; echo "Created by: " . $creator->username; ``` -------------------------------- ### PublishPoll Command Constructor Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/Commands.md Constructor for the PublishPoll command. ```php public function __construct( public int $pollId, public User $actor, public array $data ) ``` -------------------------------- ### Get All Polls in a Group Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/PollGroup.md Retrieves all polls associated with a specific poll group. Useful for displaying group-specific poll data. ```php $polls = $group->polls; // All polls in the group echo "Group contains " . $polls->count() . " polls"; foreach ($polls as $poll) { echo $poll->question . "\n"; } ``` -------------------------------- ### Querying Polls with Scopes Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/PollRepository.md Demonstrates building complex queries using query scopes to filter polls by visibility, publication status, recency, and sorting. ```php $repo = resolve(PollRepository::class); // Combination: Global, published, recent, sorted by votes $topRecent = $repo->queryVisibleTo($actor) ->whereNull('post_id') // Global only ->whereNotNull('published_at') // Published ->where('created_at', '>', now()->subDays(7)) ->orderBy('vote_count', 'desc') ->limit(10) ->get(); // Global, unpublished drafts by current user $myDrafts = $repo->queryVisibleTo($actor) ->whereNull('post_id') ->whereNull('published_at') ->where('user_id', $actor->id) ->orderBy('created_at', 'desc') ->get(); // Polls ending soon $endingSoon = $repo->queryVisibleTo($actor) ->whereNotNull('end_date') ->where('end_date', '<', now()->addDays(1)) ->where('end_date', '>', now()) ->orderBy('end_date', 'asc') ->get(); ``` -------------------------------- ### Create a Poll via Command Bus (Backend) Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/QuickStart.md This PHP code demonstrates creating a poll using the backend Command Bus. It's suitable for server-side operations. The `CreatePoll` command requires an actor, an optional post, and poll data. ```php use FoF\Polls\Commands\CreatePoll; use Flarum\Bus\Dispatcher; $bus = resolve(Dispatcher::class); $poll = $bus->dispatch(new CreatePoll( actor: $user, post: null, // Global poll data: [ 'attributes' => [ 'question' => 'What is your favorite color?', 'publicPoll' => true, 'allowMultipleVotes' => false, 'maxVotes' => 1, 'hideVotes' => false, 'allowChangeVote' => true, 'endDate' => '2026-07-01T00:00:00Z', 'isDraft' => false, 'options' => [ ['answer' => 'Red', 'imageUrl' => null], ['answer' => 'Blue', 'imageUrl' => null], ['answer' => 'Green', 'imageUrl' => null], ] ] ] )); echo $poll->id; // New poll ID ``` -------------------------------- ### Get Public Image URL Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/PollImageUploader.md Returns the public URL for a stored image file. Use this to display images in your application. ```php $url = $uploader->url('pollImage-xY7kQ2pL.webp'); // Returns: "https://example.com/storage/poll-images/pollImage-xY7kQ2pL.webp" ``` -------------------------------- ### Eager Loading Related Data Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/PollRepository.md Demonstrates how to use eager loading with `with()` to efficiently load related poll data such as options, user, and post. ```php $polls = $repository->queryVisibleTo($actor) ->with('options', 'user', 'post') ->get(); ``` -------------------------------- ### List Polls API Endpoint Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/README.md Use this GET endpoint to retrieve a list of polls. Refer to the API reference for query parameters. ```http GET /api/polls List polls ``` -------------------------------- ### Creating Polls with Options Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/PollOption.md Explains how poll options are created and included when creating a new poll via the API. ```APIDOC ## Creating Polls with Options ### Description Poll options are created as part of the main poll creation process via the API. They are not created as standalone resources. ### Method POST ### Endpoint `/polls` ### Request Body Example ```json { "data": { "type": "polls", "attributes": { "question": "What is your favorite programming language?", "options": [ {"answer": "Option A", "imageUrl": null}, {"answer": "Option B", "imageUrl": "pollOptionImage-abc.webp"}, {"answer": "Option C", "imageUrl": null} ] } } } ``` ### Validation - `answer`: Required (non-empty string, max 255 chars). - Minimum 2 options required per poll. - Maximum options depend on `fof-polls.maxOptions` setting (default 10). - `imageUrl`: Optional (filename only, max 255 chars). ``` -------------------------------- ### Convert Poll Images to WebP Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/configuration.md Use the console command to convert existing PNG poll images to WebP format, with an option to clean up the original PNG files. This optimizes image delivery. ```bash php flarum fof:polls:convert-images # Convert images php flarum fof:polls:convert-images --cleanup # Remove old PNGs ``` -------------------------------- ### GET /api/polls/{id} Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/ApiResources.md Retrieve a single poll by its ID. Includes related data like options and user's votes by default. ```APIDOC ## GET /api/polls/{id} ### Description Retrieve a single poll by its ID. Includes related data like options and user's votes by default. ### Method GET ### Endpoint /api/polls/{id} ### Parameters #### Path Parameters - **id** (string) - Required - The ID of the poll to retrieve. #### Query Parameters - **include** (string) - Optional - Related data to include. **Default includes:** - `options` - `myVotes` - `myVotes.option` ### Response #### Success Response (200 OK) - **poll data** (object) - The requested poll object. ``` -------------------------------- ### Get publicly visible polls Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/PollRepository.md Call queryVisibleTo() without any arguments to retrieve polls that are publicly visible. This is useful for displaying polls to guests. ```php $repository = resolve(PollRepository::class); // Get publicly visible polls (no specific user) $publicPolls = $repository->queryVisibleTo()->get(); ``` -------------------------------- ### Image Variants on Disk Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/types.md Illustrates the naming convention for different resolutions of an uploaded image stored on disk. ```string pollImage-xY7kQ2pL.webp (1x base, 250×250) pollImage-xY7kQ2pL@2x.webp (2x, 500×500 if exists) pollImage-xY7kQ2pL@3x.webp (3x, 750×750 if exists) ``` -------------------------------- ### Upload Image Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/PollImageUploader.md Uploads an image, auto-converting it to WebP or GIF, and generating responsive variants at 1x, 2x, and 3x resolutions. It handles filename generation with a random suffix and ensures images are not upscaled. ```APIDOC ## upload() ### Description Uploads an image, auto-converting to WebP or GIF, and generating responsive variants at 1×, 2×, and 3× resolutions. ### Method `public function upload(string $filenamePrefix, ImageInterface $image): string` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **filenamePrefix** (string) - Required - Prefix for the filename (e.g., "pollImage" or "pollOptionImage") - **image** (ImageInterface) - Required - Intervention Image instance (already loaded) ### Request Example ```php use FoF\Polls\PollImageUploader; use Intervention\Image\ImageManager; $uploader = resolve(PollImageUploader::class); $imageManager = resolve(ImageManager::class); // Load an image from upload $image = $imageManager->read($file->getStream()->getMetadata('uri')); // Upload with variants $filename = $uploader->upload('pollImage', $image); // Returns: "pollImage-xY7kQ2pL.webp" ``` ### Response #### Success Response (200) - **string** - Base filename (e.g., "pollImage-aBcDeFgH.webp") #### Response Example ```json "pollImage-xY7kQ2pL.webp" ``` ``` -------------------------------- ### Upload Image with Variants Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/PollImageUploader.md Uploads an image, converting it to WebP or GIF and generating responsive variants. Use this to upload new poll or poll option images. ```php use FoF\Polls\PollImageUploader; use Intervention\Image\ImageManager; $uploader = resolve(PollImageUploader::class); $imageManager = resolve(ImageManager::class); // Load an image from upload $image = $imageManager->read($file->getStream()->getMetadata('uri')); // Upload with variants $filename = $uploader->upload('pollImage', $image); // Returns: "pollImage-xY7kQ2pL.webp" ``` -------------------------------- ### Accessing Polls Settings Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/QuickStart.md Retrieve extension settings using the SettingsRepository. This is useful for checking feature flags or configuration values like the maximum number of options allowed. ```php use Flarum\Settings\SettingsRepositoryInterface; $settings = resolve(SettingsRepositoryInterface::class); if (!$settings->get('fof-polls.enableGlobalPolls')) { throw new PermissionDeniedException('Global polls disabled'); } $maxOptions = (int) $settings->get('fof-polls.maxOptions', 10); ``` -------------------------------- ### Get polls visible to authenticated user Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/PollRepository.md Use queryVisibleTo() with an actor to retrieve polls that are visible to a specific user. This method applies built-in visibility scopes. ```php $repository = resolve(PollRepository::class); // Get polls visible to authenticated user $visiblePolls = $repository->queryVisibleTo($actor)->get(); ``` -------------------------------- ### Paginated Poll Results Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/PollRepository.md Shows how to implement pagination for large result sets of polls using the `paginate()` method. ```php $paginated = $repository->queryVisibleTo($actor) ->paginate(20); ``` -------------------------------- ### Create a Poll Group Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/QuickStart.md Organize polls into groups by first creating a poll group via a POST request to the `/poll_groups` endpoint. Provide the desired name for the group in the request body. ```bash curl -X POST /api/poll_groups \ -H "Authorization: Bearer {token}" \ -d '{ "data": { "type": "poll_groups", "attributes": { "name": "Feature Requests" } } }' ``` -------------------------------- ### Handle Poll Votes Changed Event Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/Events.md Example of how to handle the PollVotesChanged event. This listener demonstrates refreshing the vote count for a poll, which can be useful for cache invalidation or analytics. ```php public function handle(PollVotesChanged $event) { // Refresh vote counts if needed $event->poll->refreshVoteCount()->save(); } ``` -------------------------------- ### Publish a Poll Immediately Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/QuickStart.md Publish a poll immediately by sending a POST request to the `/publish` endpoint without a `scheduledFor` attribute. This will make the poll live without delay. ```bash curl -X POST /api/polls/10/publish \ -H "Authorization: Bearer {token}" \ -d '{"data": {"type": "polls", "id": "10", "attributes": {}}}' ``` -------------------------------- ### Serializing Settings to Forum Resource Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/configuration.md Make fof/polls configuration settings available in the Flarum forum resource for frontend access. Use appropriate type casting functions like 'boolval', 'strval', and 'intval'. ```php ->serializeToForum('discussionPollsEnabled', 'fof-polls.enableDiscussionPolls', 'boolval') ->serializeToForum('pollsDirectoryDefaultSort', 'fof-polls.directory-default-sort', 'strval') ->serializeToForum('globalPollsEnabled', 'fof-polls.enableGlobalPolls', 'boolval') ->serializeToForum('pollGroupsEnabled', 'fof-polls.enablePollGroups', 'boolval') ->serializeToForum('pollMaxOptions', 'fof-polls.maxOptions', 'intval') ``` -------------------------------- ### Schedule Flarum Tasks Source: https://github.com/friendsofflarum/polls/blob/2.x/README.md Add this cron job to your crontab to enable scheduled publication of polls and other Flarum extension tasks. Ensure the path points to your Flarum installation. ```cron * * * * * cd /path/to/flarum && php flarum schedule:run ``` -------------------------------- ### Chain additional constraints on poll query Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/PollRepository.md After obtaining a base query builder with query(), you can chain additional Eloquent constraints like where() and get() to refine your poll selection. ```php $repository = resolve(PollRepository::class); // Chain additional constraints $globalPolls = $repository->query() ->whereNull('post_id') ->get(); ``` -------------------------------- ### Accessing PollOption Data in PHP Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/PollOption.md Demonstrates how to retrieve a PollOption by its ID and access its properties and relationships in PHP. Includes fetching associated votes and the parent poll. ```php use FoF\Polls\PollOption; // Find option by ID $option = PollOption::findOrFail(8); // Get votes for this option $votes = $option->votes()->get(); $voterCount = $option->votes()->count(); // Get option details echo $option->answer; // "Option A" echo $option->vote_count; // 15 (cached) echo $option->poll_id; // 5 echo $option->created_at->format('Y-m-d H:i'); // "2026-06-01 10:00" // Get parent poll $poll = $option->poll; // See who voted for this option (if public poll) $voters = $option->votes() ->with('user') ->where('created_at', '>', now()->subDay()) ->get(); ``` -------------------------------- ### Build a New Poll Instance Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/Poll.md Use the `build` static method to create and configure a new Poll instance. This method allows setting various poll parameters like question, post association, end date, and voting rules before saving. ```php use FoF\Polls\Poll; use Carbon\Carbon; $poll = Poll::build( question: 'What is your favorite feature?', postId: null, // Global poll actorId: $user->id, endDate: Carbon::now()->addDays(7), publicPoll: true, allowMultipleVotes: false, maxVotes: 1, hideVotes: false, allowChangeVote: true, subtitle: 'Help us improve the forum', imageFilename: null, imageAlt: null, publishedAt: Carbon::now() ); $poll->save(); ``` -------------------------------- ### Creating a Poll Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/README.md Use the Poll::build() method to create a new poll and then add options using the save() method on the options relationship. Alternatively, dispatch a CreatePoll command. ```php $poll = Poll::build(...)->save(); // Then add options $poll->options()->save(PollOption::build(...)); ``` ```php $bus->dispatch(new CreatePoll($actor, $post, $data)); ``` -------------------------------- ### Selecting Specific Columns Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/PollRepository.md Illustrates using `select()` to retrieve only specific columns from the polls table, optimizing performance when not all data is needed. ```php $polls = $repo->query() ->select(['id', 'question', 'user_id', 'vote_count']) ->get(); ``` -------------------------------- ### Build a new PollVote instance Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/PollVote.md Use the `build` static method to create a new `PollVote` instance without immediately saving it to the database. This is useful for preparing a vote before performing additional operations or validation. ```php use FoF\Polls\PollVote; $vote = PollVote::build( pollId: 5, userId: 123, optionId: 8 ); $vote->save(); ``` -------------------------------- ### Get recent polls visible to user with additional filters Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/PollRepository.md Combine queryVisibleTo() with other Eloquent query builder methods like where() and orderBy() to fetch specific subsets of visible polls, such as recent ones. ```php $repository = resolve(PollRepository::class); // Combine with additional filters $recentPolls = $repository->queryVisibleTo($actor) ->where('created_at', '>', now()->subDays(7)) ->orderBy('created_at', 'desc') ->get(); ``` -------------------------------- ### Listening for Poll Events Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/README.md Use the Extend\Event class to listen for poll-related events, such as PollWasCreated. ```php (new Extend\Event())->listen(PollWasCreated::class, MyListener::class) ``` -------------------------------- ### Fetching Votes via API Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/PollVote.md Retrieve poll votes using API GET requests. You can include all votes for a poll, or specifically fetch the authenticated user's votes using `myVotes`. ```http GET /api/polls/10?include=votes,votes.user ``` ```http GET /api/polls/10?include=myVotes,myVotes.option ``` -------------------------------- ### Update a Poll Group's Name via API Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/PollGroup.md Example of updating the name of an existing poll group using a PATCH request to the /api/poll_groups/{id} endpoint. Requires authentication and edit permissions. ```bash curl -X PATCH /api/poll_groups/2 \ -H "Authorization: Bearer {token}" \ -d '{ \ "data": { \ "type": "poll_groups", \ "id": "2", \ "attributes": { \ "name": "Feature Requests & Ideas" \ } \ } \ }' ``` -------------------------------- ### CreatePollGroup Command Constructor Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/Commands.md Constructor for the CreatePollGroup command. ```php public function __construct( public User $actor, public array $data ) ``` -------------------------------- ### Validation Error: Invalid DateTime Format for Scheduled Publication Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/errors.md This error occurs when the scheduled publication time is not provided in the correct ISO 8601 format with a timezone offset. Examples of valid and invalid formats are provided. ```json { "errors": [ { "status": 400, "code": "validation_error", "detail": "Scheduled time must be an ISO 8601 datetime with a timezone offset (e.g. \"2026-05-01T10:00:00Z\")." } ] } ``` -------------------------------- ### Delete a Poll Group via API Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/PollGroup.md Example of deleting a poll group using a DELETE request to the /api/poll_groups/{id} endpoint. Requires authentication and delete permissions. Associated polls will have their poll_group_id set to null. ```bash curl -X DELETE /api/poll_groups/2 \ -H "Authorization: Bearer {token}" ``` -------------------------------- ### Counting Polls Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/PollRepository.md Shows how to count polls based on different criteria, such as total visible polls, polls by type (global/discussion), and polls by status (draft/published). ```php // Total polls visible to user $count = $repo->queryVisibleTo($actor)->count(); // Count by type $globalCount = $repo->query()->whereNull('post_id')->count(); $discussionCount = $repo->query()->whereNotNull('post_id')->count(); // Count by status $draftCount = $repo->query()->whereNull('published_at')->count(); $publishedCount = $repo->query()->whereNotNull('published_at')->count(); ``` -------------------------------- ### Configure Search Driver for Polls Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/configuration.md Integrate Flarum's search functionality with the Polls extension by adding searchers for `Poll` and `PollGroup` models. This enables searching for polls and poll groups. ```php (new Extend\SearchDriver(DatabaseSearchDriver::class)) ->addSearcher(Poll::class, Filter\GlobalPollSearcher::class) ->addSearcher(PollGroup::class, Filter\PollGroupSearcher::class) ``` -------------------------------- ### Using Poll Repository for Data Access Source: https://github.com/friendsofflarum/polls/blob/2.x/_autodocs/api-reference/QuickStart.md Interact with the PollRepository to find, query, and retrieve poll data. The repository methods often include visibility checks based on the current user. ```php use FoF\Polls\PollRepository; $repo = resolve(PollRepository::class); // Find a specific poll (with visibility check) $poll = $repo->findOrFail(10, $actor); // Throws if not found/not visible $poll = $repo->find(10, $actor); // Returns null if not found/not visible // Query with visibility $visiblePolls = $repo->queryVisibleTo($actor) ->where('isGlobal', true) ->orderBy('created_at', 'desc') ->get(); // Get all polls (unfiltered) $allPolls = $repo->query()->get(); ```