Comments (11)
From my practice trying to apply DRY to controllers isn't that good idea in general. Despite being similar at the start they're often becoming too different in the development process. Code becomes complicated because of it. If there's a common part it worth moving it to a separate class that's not controller.
In Yii you can return data that's obtained not only from a View but a string or an array of data or just int return code (in case of console controllers):
public function actionTest()
{
return 'test';
}
from yii-core.
you might actually want to implement the RestController's style of handling the data if it is meant to be overriden
from yii-core.
It's all different now.
from yii-core.
Could you give concrete example?
from yii-core.
Ok, I have a CrudController which has basic functionalities for CRUD operation on a model class.
class CrudController extends Controller
{
public function actionIndex()
{
$dataProvider = new ActiveDataProvider([
'query' => call_user_func([$this->modelClass, 'find']),
]);
return $this->render($this->indexView, compact('dataProvider'));
}
}
So now I want to use my CrudController, but want to add another parameter to the view for a filter dropdown for example. So I want to do something like this:
UserController extends CrudController
{
public function actionIndex() //Override the base class
{
$view = parent::actionIndex(); //The problem is that a rendered string is returned !
//change some parameters in the view->params or change the view file
$view->params['comboData'] = $this->getComboData();
$view->viewFile = 'new_view';
//
return $view; //the actual view should be rendered in the caller function
}
}
It is a general OOP principle to be able to extend a class/method and change the way it works and its return result. Which makes it hard here because of the string returned. In this same case on a rest controller an array/object is returned which can be manipulated which is OK.
from yii-core.
@samdark overriding controllers can become a burden but that really depends on who is doing it :) and the framework shouldn't stop you. The View class itself should be generalized enough to take strings, arrays and so on and the renderer at the end of the loop should decide how to transform it.
I think that a real OOP MVC should work with view objects e.g. $this->render('view') should return a View instance with prefilled params and viewfile properties so it can be easily overridden and later on a renderer class should generate content based on the view object.
If someone is wondering I have currently worked around this issue like this :
public function actionIndex()
{
return $this->render($this->indexView, $this->getIndexData());
}
protected function getIndexData()
{
$dataProvider = new ActiveDataProvider([
'query' => call_user_func([$this->modelClass, 'find']),
]);
return compact('dataProvider');
}
The getIndexData() method can be easily extended.
from yii-core.
@nkostadinov that's how i do it in my rest api, but it returns the active query object instead
from yii-core.
I solved this problem once with using response formatter. It recognizes output array of action and renders result. Actual code:
namespace frontend\controllers\base;
use Yii;
class Controller extends \common\web\Controller
{
public static $instance;
public static $actionInstance;
public function beforeAction($action)
{
self::$instance = $this;
self::$actionInstance = $action;
return parent::beforeAction($action);
}
}
namespace frontend\components;
use frontend\controllers\base\Controller;
use Yii;
use yii\web\HtmlResponseFormatter;
use yii\web\Response;
class RenderFormatter extends HtmlResponseFormatter
{
public function format($response)
{
if ($response->content) {
return;
}
if (is_array($response->data) && isset(Controller::$instance) && isset(Controller::$actionInstance)) {
$data = $response->data;
Controller::$instance->action = Controller::$actionInstance;
Yii::$app->controller = Controller::$instance;
if (!isset($data['params'])) {
$data = ['params' => $data];
}
if (!isset($data['viewFile'])) {
$data['viewFile'] = Controller::$actionInstance->id;
}
if (!isset($data['render']) || !in_array($data['render'], ['render', 'renderAjax', 'renderPartial'])) {
$data['render'] = 'render';
}
$response->content = Yii::$app->controller->{$data['render']}($data['viewFile'], $data['params']);
Yii::$app->controller->action = null;
Yii::$app->controller = null;
} else {
parent::format($response);
}
Controller::$actionInstance = null;
Controller::$instance = null;
}
}
- There is some hacks with controller and action instances
- This is ugly
- There is no really need to do that - I checked 😄 . I'm fully agree with @samdark
from yii-core.
@AnatolyRugalev yes, that's how I'd do it but same as you I've figured out about 3.
.
from yii-core.
Well I did it like this and for now. This is in my base controller :
public function render($view, $params = [])
{
$return new View([
'viewFile' => $view,
'params' => $params,
]);
}
public function runAction($id, $params = [])
{
$result = parent::runAction($id, $params);
if($result instanceof View)
$result = parent::render($result->viewFile, $result->params);
return $result;
}
from yii-core.
The same problem applies to overriding actions
defined in parent Controller
.
As an example if I have basic CRUD actions defined in parent controller (external actions), and I want to override just one of them in child with inline action, there's no way to do it.
Though I think it's a separate issue.
from yii-core.
Related Issues (20)
- `data` dirs in tests HOT 5
- Debug code in Model? HOT 3
- \yii\base\Application constructor parameter HOT 2
- 我认为yii3最应该解决的就是composer包过大的问题 HOT 2
- Should not require yii-web HOT 11
- Enhancement: BaseJson::decode supports decode options HOT 1
- Discuss: Do we still need controllers? HOT 2
- Enhancement: StringHelper::isEmpty() HOT 7
- can't visit yii forum site HOT 1
- Review helpers naming and usage HOT 33
- Url::ensureScheme should fail hard for non absolute paths HOT 2
- What is the current dependency between repo? HOT 20
- Yii3 assets path not correctly reference if installed in subfolder HOT 2
- SOLID compliance HOT 3
- Custom reference syntax to class or class member in comments make impossible to navigate in IDE HOT 19
- Change namespace to Yiisoft\Core? HOT 8
- When will yii3 be released? HOT 1
- Request to separate FileHelper from yii-core HOT 19
- Pack requirements checker into separate package HOT 1
- Repo merges into a repo and then splits HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from yii-core.