How does Joomla Model View Controller (MVC) work? - php

I am new to Joomla, I want to know how the Joomla controller passes data to the model, model to controller and controller to view. Although this might be a silly question, I really tried to find the answer. I hope I can get some help from the stackoverflow family.

The controller picks up the view variable in the url and using these determines which view needs to be used. It then sets the view to be used. The view then calls the model to fetch the data it requires and then passes this to the tmpl to be displayed.
Below is a simple setup of how this all works together:
components/com_test/controller.php
class TestController extends JController
{
// default view
function display() {
// gets the variable some_var if it was posted or passed view GET.
$var = JRequest::getVar( 'some_var' );
// sets the view to someview.html.php
$view = & $this->getView( 'someview', 'html' );
// sets the template to someview.php
$viewLayout = JRequest::getVar( 'tmpl', 'someviewtmpl' );
// assigns the right model (someview.php) to the view
if ($model = & $this->getModel( 'someview' )) $view->setModel( $model, true );
// tell the view which tmpl to use
$view->setLayout( $viewLayout );
// go off to the view and call the displaySomeView() method, also pass in $var variable
$view->displaySomeView( $var );
}
}
components/com_test/views/someview/view.html.php
class EatViewSomeView extends JView
{
function displaySomeView($var) {
// fetch the model assigned to this view by the controller
$model = $this->getModel();
// use the model to get the data we want to use on the frontend tmpl
$data = $model->getSomeInfo($var);
// assign model results to view tmpl
$this->assignRef( 'data', $data );
// call the parent class constructor in order to display the tmpl
parent::display();
}
}
components/com_test/models/someview.php
class EatModelSomeView extends JModel
{
// fetch the info from the database
function getSomeInfo($var) {
// get the database object
$db = $this->getDBO();
// run this query
$db->setQuery("
SELECT
*
FROM #__some_table
WHERE column=$var
");
// return the results as an array of objects which represent each row in the results set from mysql select
return $db->loadObjectList();
}
}
components/com_test/views/someview/tmpl/someviewtmpl.php
// loop through the results passed to us in the tmpl
foreach($this->data as $data) {
// each step here is a row and we can access the data in this row for each column by
// using $data->[col_name] where [col_name] is the name of the column you have in your db
echo $data->column_name;
}

check out this site for detailed tutorial on how to make components and modules using Joomla's MVC. Hope it helps
https://docs.joomla.org/Developing_a_MVC_Component

Also refer official joomla doc for detailed tutorial on how to make components and modules using Joomla's MVC. Hope it helps
http://docs.joomla.org/Developing_a_Model-View-Controller_Component/1.5/Introduction

Related

Add a custom attribute when retrieving a model

Is possible to attach a custom attribute when retrieving a model in laravel?.
The problem is that I need to return some data that is not in the database along the info from the database. I've been doing it manually but I guess that there might be a way to do it in the model.
Example: I have an application table. Each application contains a folder with documents with the same application id. I need to attach the amount of files the folder that correspond to each application.
This is what I do:
$application = Application::get();
$application = $application->map(function($a){
$a->files = $this->getFiles($a->id); // This gets the amount of files
return $a;
})
Is there some way to do it in the model in a way that $application->files is already contained in $application when doing Application::get()
class User extends Model
{
public function getFooBarAttribute()
{
return "foobar";
}
}
And access to that attribute like:
$user->foo_bar;
or like,
$user->fooBar;
More detailed documentation;
https://laravel.com/docs/5.7/eloquent-mutators#defining-an-accessor
in the Application model
public function getFilesAttribute()
{
return 'lala'; // return whatever you need;
}
now application model has an attribute named files.
$application->files // returns lala.
example code.
$applications = Application::get();
$application_files = applications->map->files;
official documentation https://laravel.com/docs/5.7/eloquent-mutators#defining-an-accessor

Yii 1.1.16, how to detect action, what is runned from code?

i have small trouble...
class Controller {
init() {
// initializing...
// render header && footer
$header = (new HeaderAction)->run();
$footer = (new FooterAction)->run();
// redirect to called action, what renders all the content
}
}
What i can detect diff between ->run() and called action?
Answer found in:
AfterRender -> parse Route -> compare action names. If match - echo, if not match - Return.
Yii is SHIT!!!
I will write new class MyAction with method AddData, what can render for me some viewfile. Creating class CAction for this, what can't rendering? Maybe i must create controller? Are you noob, Quang, ha?
Lol, i can't create the header with action. I must create it in Controller. Controller file now is 1200 lines. >_<
class MyAction {
public $data = array();
public function addData($name, $val) {
$this->data[$name] = $val;
}
public function render($file) {
ob_start;
// ... something
return ob_get_clean;
};
}
/// ITS ALL WHAT NEED ALL THE DEVELOPERS>>>>
BEHAVIORS? EVENTS? FILTERS? WIDGETS? MODULES? MAYBE WE NEED "CAMOBAP" AS AUTOCAR?
REASOOOONS????
===
Lol, there is model cannot to render at all. I have products with views as "tr-tr", and i must create controller, create action, create route for rendering funcking 10 SYMBOLS.... Its Rage. About u, Quang.
Russian Bear will kill you.

Zend Framework 2: Composing web page of several parts

I need to compose a web page of several view templates (the view template rendering page content and a view template rendering sidebar). In my layout.phtml, I have two variable placeholders: $content and $sidebar:
......
<?php echo $this->sidebar; ?>
......
<?php echo $this->content; ?>
......
In my controller's action, I pass the data to these view templates through the ViewModels chained in a tree:
public function indexAction() {
// Preparing my data
// $form = ...
// $menuItems =
// $activeItem =
// Create sidebar view model
$sidebarViewModel = new ViewModel(array('menuItems'=>$menuItems, 'activeItem'=>$activeItem));
// Add it as a child to layout view model
$this->layout()->addChild($sidebarViewModel, 'sidebar');
// Page content view model
$viewModel = new ViewModel(array('form'=>$form));
return $viewModel;
}
But, because I have the sidebar on every page, I will have to copy and paste this code for every action of every controller. Is there any recommended way of reusing the code that populates the ViewModel for sidebar?
One approach would be to achieve this with a controller plugin.
Assuming you have wired it up with appropriate config, and you're in the Application module.
In module/Application/src/Application/Controller/Plugin/AddSidebar.php:
namespace Application\Controller\Plugin;
use Zend\Mvc\Controller\Plugin\AbstractPlugin;
class addSidebar extends AbstractPlugin {
public function __invoke($menu, $active) {
// create new view model
$sidebarVM = new ViewModel(array(
'menuItems' => $menu,
'activeItem' => $active
));
// add it to the layout
$this->getController()->layout()->addChild($sidebarVM, 'sidebar');
}
}
Then in each of your controllers:
$this->addSidebar($menuItems, $activeItem);
Another (probably better) option would be to hook into the render MvcEvent and add the sidebar there. You'd have to work out how to generate $menuItems and $activeItem in that context however.

Managing different output formats or device-types

I have to display different views for mobile devices and I want to provide a simple JSON-API.
I wrote a little module for the Kohana Framework which loads different views depending on some circumstances, which should help me in this case: https://github.com/ClaudioAlbertin/Kohana-View-Factory
However, I'm not very happy with this solution because I can't set different assets for different device-types. Also, when I'd output JSON with a JSON-view, it's still wrapped in all the HTML-templates.
Now, I'm looking for a better solution. How do you handle different output formats or device-types in your MVC-applications?
I had an idea: just split the controller into two controllers: a data-controller and an output-controller.
The data-controller gets and sets data with help of the models, does
all the validating etc. It gets the data from the models and write it to a data-object
which is later passed to the view.
The output-controller loads the views and give them the data-object from the data-controller. There is an output-controller for each format or device-type: an output-controller for mobile-devices could load the mobile-views and add all the mobile-versions of stylesheets and scripts. A JSON-output-controller could load a view without all the html-template stuff and convert the data into JSON.
A little example:
<?php
class Controller_Data_User extends Controller_Data // Controller_Data defines a data-object $this->data
{
public function action_index()
{
$this->request->redirect('user/list');
}
public function action_list()
{
$this->data->users = ORM::factory('user')->find_all();
}
public function action_show($id)
{
$user = new Model_User((int) $id);
if (!$user->loaded()) {
throw new HTTP_Exception_404('User not found.');
}
$this->data->user = $user;
}
}
class Controller_Output_Desktop extends Controller_Output_HTML // Controller_Output_HTML loads a HTML-template
{
public function action_list($data)
{
$view = new View('user/list.desktop');
$view->set($data->as_array());
$this->template->body = $view;
}
public function action_show($data)
{
$view = new View('user/show.desktop');
$view->set($data->as_array());
$this->template->body = $view;
}
}
class Controller_Output_JSON extends Controller_Output // Controller_Output doesn't load a template
{
public function action_list($data)
{
$view = new View('user/list.json');
$view->users = json_encode($data->users->as_array());
$this->template = $view;
}
public function action_show($data)
{
$view = new View('user/show.json');
$view->user = json_encode($data->user);
$this->template = $view;
}
}
What do you think?
Hmm... From the 1st view it loooks strange, and somehow like fractal -- we are breaking on MVC one of our MVC -- C.
But why is this app returns so different results, based on point-of-entry (or device)?
The task of the controller is only to get the data and choose the view -- why do we need standalone logic for choosing something based on point-of-entry (device)?
I think these questions should be answered first. Somewhere could be some problem.
Also the cotroller should select only one view ideally, and dont' do "encode" or else with data, based on current output. I think all this should be in some kind of "layouts" or else. As data always the same and even different views should be the same -- only some aspects changes.

Dynamic pages in cakePHP

So I've been creating my first client website with cakePHP, and have run into a problem.
I'm trying to create a system similar to WordPress where you can create new pages (simply title, slug and content), and they are served up to their slug address (i.e. About will be available at mysite.com/about).
I've created my own controller & model for 'Pages' (overwriting the core pages controller), and have set up simple functions (view, admin_add, admin_delete). My model is simple, just the $name so it can connect to the db.
I'm pretty sure my problem lies in config/routes.php. Here is the code I'm currently using:
App::import('model', 'Page');
$Page = new Page();
$pages = $Page->find('list', array('fields' => array('id', 'slug')));
Router::connect('/:pages', array('controller' => 'pages'), array('Page' => implode($pages, '|')));
It just doesn't work though. When I visit an page I have (i.e. mysite.com/newpage), it tells me the newpage controller can't be found.
PLEASE HELP! I'm on a tight deadline :)
Thanks,
~harley
You need to extend the Class CakeRoute. Put your custom model code in there, and then pass that class name to your route definition in routes.php
routes.php would look something like this.
App::import('Lib', 'routes/MyCustomRoute');
Router::connect('/:page', array('controller'=>'pages', 'action'=>'display'), array('routeClass' => 'MyCustomRoute'));
Then over in libs/routes/my_custom_route.php
class MyCustomRoute extends CakeRoute {
function parse($url) {
$params = parent::parse($url);
//import your model
App::import('Model','Page');
//create model object
$Page = new Page();
//find using $params['page'];
if($Page->find('first', array('conditions'=>array('page.slug'=>$params['page'])))){
//return $params if successfull match
return $params
} else
return false;
//return false to fall through to next route.
}

Categories