1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.

Stuck With ControllerPublic & DataWriter For My Addon

Discussion in 'XenForo Development Discussions' started by TheBigK, Jan 4, 2015.

  1. TheBigK

    TheBigK Well-Known Member

    I'm a total n00b to XF development and PHP as well and stuck with the code. It'd be really nice if you could help with the following.

    Addon Idea: 'Invite Me'
    What It Does: Shows a button that says "I'm Interested", which when clicked, registers the Username of the user in a database table. If the user has already clicked the button, it will appear disabled with a message "You're already in the invite list".

    The admin gets to see the list of all of the users who have clicked the button in the admin control panel as
    [Username] |

    What I've done so far:-

    1. I began developing this addon by first creating the Route Prefix:-
    PHP:
    <?php

    class InviteMe_Prefix_Route_Index implements XenForo_Route_Interface
    {
        public function 
    match($routePathZend_Controller_Request_Http $requestXenForo_Router $router)
        {
            return 
    $router->getRouteMatch('InviteMe_ControllerPublic_Index',$routePath);
        }
    }
    2. I then created ControllerPublic as follows [This one is messy and I'm stuck here]

    PHP:
    <?php

    class InviteMe_ControllerPublic_Index extends XenForo_ControllerPublic_Abstract
    {

        public function 
    actionIndex()
        {
            
    //Get InviteMeModel
            
    $inviteMeModel $this->getModelFromCache('InviteMe_Model_Invite');

            
    //Get information about the visitor
            
    $visitor XenForo_Visitor::getInstance();

            
    //Get the list of existing applicants
            
    $alreadyApplied $inviteMeModel->getApplied();

            
    //Check if user's username already exists in our invite table
            
    if (in_array($visitor['username'], $alreadyApplied))
            {
                return 
    $this->responseError('You are already in our waiting list.');
            }

            
    $viewParams = array($visitor['username']);
            return 
    $this->responseView('InviteMe_ViewPublic_Index''inviteMe'$viewParams);

        }

        public function 
    actionAcceptInvite()
        {
            
    //Make this a POST action
            
    $this->_assertPostOnly();

            
    //Get information about the visitor
            
    $visitor XenForo_Visitor::getInstance();

            
    //Make this available for registered members only
            
    $this->_assertRegistrationRequired();

            
    //Create A DataWriter To Save The User ID To Database
            
    $dw XenForo_DataWriter::create('InviteMe_DataWrite_Index');
            
    $dw->set('user_id'$visitor['username']);
            
    $dw->save();

            return 
    $this->responseRedirect(XenForo_ControllerResponse_Redirect::SUCCESSXenForo_Link::buildPublicLink('invite'));
        }
    }
    3. DataWriter:

    PHP:
    <?phpclass InviteMe_DataWriter_Index extends XenForo_DataWriter
    {
    protected function 
    _getExistingData($data)
    }
    Questions:

    1. I've been told that this one won't need a DataWriter and I can achieve saving of the username through a query. But, that'd be 'optimisation' :) . I wish to understand how to write this controller that uses a datawriter.

    2. I've absolutely no clue about the $viewParams - and what should it have for the approach that I've adopted.

    3.
    //Get information about the visitor
    $visitor = XenForo_Visitor::getInstance();

    Why is it that I can't use $visitor defined in my actionIndex() in actionAcceptInvite(), without having to declare it again? Isn't it 'public' and should be usable throughout the class?
     
  2. Chris D

    Chris D XenForo Developer Staff Member

    I would always recommend using the DataWriter for everything. It should be clear from the existing XenForo code how these work, they are used extensively.

    PHP:
    $viewParams = array(
        
    'paramNameInTemplate' => 'value'
    );
    That would make {$paramNameInTemplate} available in the template with a value of 'value'.

    No. In this context variables are only valid in the function in which they are defined
     
  3. TheBigK

    TheBigK Well-Known Member

    Yep, I got that already. But given the simplicity of the addon, I'm wondering if it's necessary to define the $viewParams? Can I end my action without setting up 'something' for the $viewParams?

    I wish to understand, why is it so?

    Also, is it okay to define it twice like I did? If not - what's the suggested approach? I'm not sure if I should really have the action for button press (that is actionAcceptInvite() ) should be clubbed with actionIndex().
     
  4. Chris D

    Chris D XenForo Developer Staff Member

    View params can be an empty array. It passes variables from the controller to the template. $visitor is automatically available to templates therefore you should be able to just do:
    PHP:
    $viewParams = array();
    That's just how PHP works. Variables defined in functions are considered to be "local" to that function.

    Twice as in once in one function and once in another function? Of course. If you need the $visitor object in multiple functions, that's really the only viable solution.

    Either is valid, but you can indeed merge the two.

    PHP:
    if ($this->isConfirmedPost())
    {
        
    // do stuff here if the action has been accessed via a POST request (e.g. submitting a form)
    }
    else
    {
        
    // do stuff here if the action has been accessed via a GET request, (e.g. clicking a link)
    }
     
    TheBigK likes this.
  5. TheBigK

    TheBigK Well-Known Member

    Thanks a LOT, Chris!

    Let me see how far I can take this. :cool:
     
  6. TheBigK

    TheBigK Well-Known Member

    Update: I got back to developing this and think I did make some progress.

    1. I decided to keep things extremely simple; and removed the check to see if user has already registered. I updated the ControllerPublic as follows:
    PHP:
    <?php

    class InviteMe_ControllerPublic_Index extends XenForo_ControllerPublic_Abstract
    {
        public function 
    actionIndex()
        {
            
    //Get Visitor Details
            
    $userID XenForo_Visitor::getUserId();

            
    //Create a new dataWriter

            
    $dW =XenForo_DataWriter::create('InviteMe_DataWriter_Index');
            
    $dW->set('user_id',$userID);
            
    $dW->save();

            
    $viewParams = array();
            return 
    $this->responseView('InviteMe_ViewPublic_Index''inviteme_index'$viewParams);
        }

    }
    2. Since I'm not going to need any of the DataWriter functions; and the system won't let me create an empty class; I decided to create empty functions -
    PHP:
    <?php
    class InviteMe_DataWriter_Index extends XenForo_DataWriter
    {
        protected function 
    _getExistingData($data)
        {
    //EMPTY 
        
    }
        protected function 
    _getFields()
        {
    //EMPTY
        
    }
        protected function 
    _getUpdateCondition($tableName)
        {
    //EMPTY
        
    }
    }
    Question: Does it all look 'okay' so far? I'm focused on being right than writing optimised code.

    3. Next: ViewPublic.

    Need some handholding here. Most of the addons I've seen seem to be rendering JSON. I've ZERO clue whether I should render HTML or JSON - and why? What exactly should viewPublic do - and how's it going to be different from a template? :sick:
     
  7. Mr. Goodie2Shoes

    Mr. Goodie2Shoes Well-Known Member

    So you are not going with showing the form with the "Invite Me" button to the visitor first?
     
  8. TheBigK

    TheBigK Well-Known Member

    Umm, the workflow I've planned is this:-

    1. User goes to -> domain/inviteme/
    2. Is presented with a big ass button that says "Invite Me"
    3. Clicks On the button -> and gets redirected to index page or home page.

    I'm not performing any check on whether they have already registered in my first version. I'm not sure if my approach doesn't show the button the the visitor. :confused:
     
  9. NixFifty

    NixFifty Well-Known Member

    I'm on my phone at the moment so I haven't been able to look in to detail.

    Your actionIndex function looks like its handling the logic for item 3 in your workflow. So when you go to /inviteme the visitor's user ID will be logged straight away, without them clicking a button. Then they'll be sent to the index template.

    Is that what you want?
     
    TheBigK likes this.
  10. TheBigK

    TheBigK Well-Known Member

    Hmm! I think I got the problem with my code. actionIndex will be automatically executed, right? So that'd quickly register the user and then take me to the index page.

    I think I should create a different action. Say actionClickButton()?
     

Share This Page