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

Controllers and Model help

Discussion in 'XenForo Development Discussions' started by Lee, Jun 14, 2013.

  1. Lee

    Lee Well-Known Member

    Hi guys, me again.

    Just trying to learn some stuff to build a very, very simple article display system.

    What I have got is the following directory structure for my application;

    Homepage
    - ControllerPublic
    - Index.php

    - Model
    - Home.php

    - Route
    - Prefix
    -Index.php

    In my ControllerPublic/Index.php file I have;

    PHP:
    <?php

    class Homepage_ControllerPublic_Index extends XenForo_ControllerPublic_Abstract
    {
        public function 
    actionIndex()
        {
            
    // Get the model class for the homepage
            
    $homeModel $this->getHomeModel();

            
    // Set the maximum amount of articles required - commented out as I haven't setup the option yet.
            // $maxArticles = XenForo_Application::get('options')->ArticleMax;

            // Get the latest articles
            
    $latestArticles $this->getLatestArticles($maxArticles);
            
    // read the date of the most recent note
            
    if ($latestArticles)
            {
                
    $date $latestArticles[0]['post_date'];
            }
            else
            {
                
    $date 0;
            }
            
    // put the data into an array to be passed to the view so the template can use it
            
    $viewParams = array(
                
    'articles' => $articles,
                
    'date' => $date
            
    );
            
    // return a View (Article_ViewPublic_Index) using template 'Article_index'
            
    return $this->responseView(
                
    'Hpmepage_ViewPublic_Index',
                
    'Article_index',
                
    $viewParams
            
    );
     
        }
    }
    In my Model/Home.php file I have;
    PHP:
    <?php

    class Homepage_Model_Home extends XenForo_Model
    {
        public function 
    getLatestArticles($maxArticles 0)
        {
            
    $sql '
                SELECT
                    articles.*,
                    user.*
                FROM xf_articles AS articles
                LEFT JOIN xf_user AS user
                ORDER BY post_date DESC
            '
    ;
            
    // ensure we have a meaningful value for $maxArticles
            
    if ($maxArticles max($maxArticles0))
            {
                
    // build our LIMIT (or equivalent) clause
                
    $sql $this->limitQueryResults($sql$maxArticles);
            }
            return 
    $this->_getDb()->fetchAll($sql);
        }
    }
    and in my route/prefix/index.php file I have;
    PHP:
    <?php

    class Homepage_Route_Prefix_Index implements XenForo_Route_Interface
    {
        
    /**
        * Match a specific route for an already matched prefix.
        *
        * @see XenForo_Route_Interface::match()
        */
        
    public function match($routePathZend_Controller_Request_Http $requestXenForo_Router $router)
        {
            return 
    $router->getRouteMatch('Homepage_ControllerPublic_Index'$routePath);
        }
    }
    What I am trying to do, is when navigating to the url /home/ I select some articles from a database and pass them to a template for display.

    I have the database setup correctly for this.

    If I remove the code from ControllerPublic/Index.php and just display;
    PHP:
    <?php

    class Homepage_ControllerPublic_Index extends XenForo_ControllerPublic_Abstract
    {
        public function 
    actionIndex()
        {



            
    // return a View (Article_ViewPublic_Index) using template 'Article_index'
            
    return $this->responseView(
                
    'Hpmepage_ViewPublic_Index',
                
    'Article_index'
            
    );
     
        }
    }
    My template Article_index displays no problem.

    But as soon as I try and call the model, I get the following error;
    Just hoping someone can point me in the right direction here, as I am stumped. I assume i'm not calling the model correctly, which means its not looking in the right place for it. But, I am unsure as to where to go from here.

    Thanks for any help anybody can offer.


    Regards,
    Lee (y)
     
  2. Chris D

    Chris D XenForo Developer Staff Member

    PHP:
    $homeModel $this->getHomeModel();
    This.

    The error is "Call to undefined method .... getHomeModel".

    So the error message is tell you that you're calling a method ($this->getHomeModel()) and it doesn't exist.

    The file that occurs in is Homepage/ControllerPublic/Index.php.

    So, do you have a function in that file called getHomeModel?

    You don't.

    So the solution would be to add this to you Index.php controller:

    PHP:
    protected function getHomeModel()
    {
        return 
    $this->getModelFromCache('Homepage_Model_Home');
    }
     
  3. Lee

    Lee Well-Known Member

    Thanks chris, I tweaked it a little and I now have this (Which I assume just does what you suggested, just without the need for a new function...).
    PHP:
    <?php

    class Homepage_ControllerPublic_Index extends XenForo_ControllerPublic_Abstract
    {
        public function 
    actionIndex()
        {
            
    // Get the model class for the homepage
            
    $homeModel $this->getModelFromCache('Homepage_Model_Home');
            
    // Set the maximum amount of articles required
            
    $maxArticles XenForo_Application::get('options')->ArticleMax;
            
    // Get the latest articles
            
    $latestArticles $homeModel->getLatestArticles($maxArticles);
            
    // read the date of the most recent note
            
    if ($latestArticles)
            {
                
    $date $latestArticles[0]['post_date'];
            }
            else
            {
                
    $date 0;
            }
            
    // put the data into an array to be passed to the view so the template can use it
            
    $viewParams = array(
                
    'articles' => $articles,
                
    'date' => $date
            
    );
            
    // return a View (Article_ViewPublic_Index) using template 'Article_index'
            
    return $this->responseView(
                
    'Hpmepage_ViewPublic_Index',
                
    'Article_index',
                
    $viewParams
            
    );
          
        }
    }
    in my ControllerPublic/Index.php file.

    I am now presented with this error;
    I assume I have done something very silly in my model class, with the select query. But I am just learning. I've tried limiting the query to its most basic form and running;

    PHP:
        public function getLatestArticles($maxArticles 0)
        {
            
    $sql '
                SELECT
                    *
                FROM xf_articles
            '
    ;

            
    // ensure we have a meaningful value for $maxArticles
            
    if ($maxArticles max($maxArticles0))
            {
                
    // build our LIMIT (or equivalent) clause
                
    $sql $this->limitQueryResults($sql$maxArticles);
            }

            return 
    $this->_getDb()->fetchAll($sql);
        }

    }

    which works, but then returns an error about $articles being undefined back in the controller.

    I'm trying to save all the aspected of xf_articles and xf_users (author only) in an array that I can use in the templates, but i'm not quite sure i'm approaching this right.
     
  4. Chris D

    Chris D XenForo Developer Staff Member

    I think you're on the right lines.

    If you look at your controller, you will see that $articles isn't actually defined anywhere:

    PHP:
    $viewParams = array(
        
    'articles' => $articles,
        
    'date' => $date
    );
    It should be:

    PHP:
    $viewParams = array(
        
    'articles' => $latestArticles,
        
    'date' => $date
    );
    Also, if your xf_articles table contains a user_id field then you should be able to do a join in your query so you can join the articles table to the xf_user table on the user_id. But you're doing it right: if things don't work, scale them right back and do them as simple as possible. Then build upon it each time.

    Your main focus should be getting any data whatsoever out of the query and displaying it in the page. Once you've got that working you can focus on limiting it, joining to other tables etc. Get the basics right first.
     
    Steve F and Lee like this.
  5. Lee

    Lee Well-Known Member

    Right, I have managed to work it back so that the query executes with no errors.

    My next question, what variables would I use to display my information in the template?
     
  6. Nobita.Kun

    Nobita.Kun Well-Known Member

    In template you can used:
    Code:
    $articles
    and
    $date
    As you see:
    Code:
    $viewParams = array(
        'articles' => $latestArticles,
        'date' => $date
    );
     
    Chris D likes this.
  7. Lee

    Lee Well-Known Member


    What I want to be able to do is take each field from the database and give it its own variable. I'm assuming, using an array.
     
  8. Lee

    Lee Well-Known Member

    What I have done is modified (again) my controller to manually set the variables i'm looking for in the template. This seems to work, but hopefully I don't need to do that for everything I want to display?

    PHP:
    <?php

    class Homepage_ControllerPublic_Index extends XenForo_ControllerPublic_Abstract
    {
        public function 
    actionIndex()
        {
            
    // Get the model class for the homepage
            
    $homeModel $this->getModelFromCache('Homepage_Model_Home');
            
    // Set the maximum amount of articles required
            
    $maxArticles XenForo_Application::get('options')->ArticleMax;
            
    // Get the latest articles
            
    $latestArticles $homeModel->getLatestArticles($maxArticles);
            
    // read the data from the articles
            
    if ($latestArticles)
            {
                
    $date $latestArticles[0]['post_date'];
                
    $articletitle $latestArticles[0]['title'];
                
    $article $latestArticles[0]['article'];
            }
            else
            {
                
    $date 0;
            }
            
    // put the data into an array to be passed to the view so the template can use it
            
    $viewParams = array(
                
    'articles' => $article,
                
    'title' => $articletitle,
                
    'date' => $date
            
    );
            
    // return a View (Article_ViewPublic_Index) using template 'Article_index'
            
    return $this->responseView(
                
    'Hpmepage_ViewPublic_Index',
                
    'Article_index',
                
    $viewParams
            
    );
          
        }
    }
    Now, i'm only displaying one result here - do I need to do a foreach() in the code to get them all to display? I've manually added another three items to the dB - but to no avail.
     
  9. Nobita.Kun

    Nobita.Kun Well-Known Member

    Why you dont use:
    PHP:
            // put the data into an array to be passed to the view so the template can use it
            
    $viewParams = array(
                
    'articles' => $latestArticles
            
    );
    In your template you can use <xen:foreach
    Code:
    <xen:foreach loop="$articles" value="$article">
    {$article.articles} - {$article.title} - <xen:datetime time="$article.date" />
    </xen:foreach>
    
     
    Lee and Chris D like this.
  10. Lee

    Lee Well-Known Member

    Thanks! Ill sort that when I get home! This was along what I was thinking would be needed so I must be learning something, lol
     
  11. Lee

    Lee Well-Known Member

    That worked, I have also managed to edit the model to run another SQL query to build the navigation.

    Next step, I am looking to turn {$article.title} into a link to the actual article. I want to build a url as follows;

    localhost/dev/home/categoryname.id/articlename.id

    categoryname.id is the page that displays all articles belonging to x and articlename.id is the article itself.

    Would I need new models and controllers to do this, or could I just use the same one?
     
  12. Lee

    Lee Well-Known Member

    I assume, as they will be new pages they will need their own models and controllers. Especially models. Just not sure if I am going about this right. :)
     

Share This Page