Yii2: standalone action does not work in event handler - php

I'm a beginner in Yii, so don't know, how to solve my problem in most correct way.
There are 2 controllers - SiteController and UsersController. I need to retrieve some data from DB and output it in layout. In particular, if user1 and user2 added user3 as friend, user3 will see it on main menu panel:
User have to see it regardless of controller, action of which is running (in pic above user sees /site/profile page, but a lot of other pages (in particular invitations) render by users controller).
I wrote the same actions in 2 controllers:
public function getStats () { //it duplicates in UsersController and SiteController
$recieved_invitations = Invitations::find()->where(['recipient_id'=>\Yii::$app->user->id])->all();
...
return [$recieved_invitations_count, $received_docs_count];
}
I decided, that, if count need to be in every page, I need trigger it regardless of controllers. So, I wrote in wep.php:
'on beforeAction' => function ($event) {
\Yii::$app->session->set('stats', $event->sender->controller->getStats());
}
And then in menu in layout I retrieve session vars.
Everything works fine. But getStats() action duplicates in controllers. I want to do it standalone.
//action code (in '#app/components' folder) (just from documentation):
namespace app\components;
use yii\base\Action;
class HelloWorldAction extends Action {
public function run() {
return "Hello World";
}
}
//in 'actions()' in controllers:
parent::actions();
return [
'hv' => [
'class' => 'app\components\HelloWorldAction',
]
];
//in 'web.php':
'on beforeAction' => function ($event) {
\Yii::$app->session->set('stats', $event->sender->controller->hv());
}
But exception throws: Calling unknown method: app\controllers\UsersController::hv(). Also: if I disable urlManager in config. file and comment out beforeAction handler, action is accessible via this URL:
http://localhost:8001/index.php?r=users%2Fhv
Why standalone action fails, if it triggers on beforeAction event? And, if it's normal behaviour, what can I do to avoid duplicating getStats() method?

I would actually try to move the getStats method to your User model, that way you can just access it from anywhere in your application by calling it like this:
Yii::$app->user->identity->stats;
// OR
Yii::$app->user->identity->getStats();
It's usually better to have fat models, simple controllers and views.

Related

How to make the controller data override view controller in Laravel?

To build a sidebar that has a lot of dynamic data on it I learned about View composers in Laravel. The problem was that View Composers trigger when the view loads, overriding any data from the controller for variables with the same name. According to the Laravel 5.4 documentation though, I achieve what I want with view creators :
View creators are very similar to view composers; however, they are
executed immediately after the view is instantiated instead of waiting
until the view is about to render. To register a view creator, use the
creator method:
From what I understand, this means if I load variables with the same name in the controller and the creator, controller should override it. However this isn't happening with my code. The view composer:
public function boot()
{
view()->creator('*', function ($view) {
$userCompanies = auth()->user()->company()->get();
$currentCompany = auth()->user()->getCurrentCompany();
$view->with(compact('userCompanies', 'currentCompany'));
});
}
And here is one of the controllers, for example:
public function name()
{
$currentCompany = (object) ['name' => 'creating', 'id' => '0', 'account_balance' => 'N/A'];
return view('companies.name', compact('currentCompany'));
}
the $currentCompany variable in question, for example, always retains the value from the creator rather than being overridden by the one from the controller. Any idea what is wrong here?
After some research, I realized my initial assumption that the data from the view creator can be overwritten by the data from the controller was wrong. The creator still loads after the controller somehow. But I found a simple solution.
For those who want to use View composers/creators for default data that can get overwritten, do an array merge between the controller and composer/creator data at the end of the boot() method of the composer/creator, like so:
$with = array_merge(compact('userCompanies', 'currentCompany', 'currentUser'), $view->getData());
$view->with($with);

Yii passing value from one controller to another

I am using Yii framework for my application. My application contain 4 controllers in which I want to pass value from one controller to another.
Let us consider site and admin controller. In site controller, I manage the login validation and retrieves admin id from database. But I want to send admin id to admin controller.
I try session variable, its scope only within that controller.
Please suggest the possible solution for me.
Thanks in advance
You want to use a redirect:
In the siteController file
public function actionLogin()
{
//Perform your operation
//The next line will redirect the user to
//the AdminController in the action called loggedAction
$this->redirect(array('admin/logged', array(
'id' => $admin->id,
'param2' => $value2
)));
}
in the adminController file
public function loggedAction($id, $param2)
{
//you are in the other action and params are set
}

Yii Route All Actions To One Method In Controller

I'm trying to make a cms like app using Yii. The functionality is going to be something like:
http://www.example.com/article/some-article-name
What I am trying to do is have everything go the method actionIndex() in the ArticleController.php, and have that one method determine how to handle the action. So my question is how can I route all actions to one method in a controller in Yii?
In your case, I think it'll be better to use either a filter or a beforeAction method.
Filter way:
Filter is a piece of code that is configured to be executed before and/or after a controller action executes.
Sample:
class SomeController extends Controller {
// ... other code ...
public function filters() {
return array(
// .. other filters ...
'mysimple', // our filter will be applied to all actions in this controller
// ... other filters ...
);
}
public function filterMysimple($filterChain) { // this is the filter code
// ... do stuff ...
$filterChain->run(); // this bit is important to let the action run
}
// ... other code ...
}
beforeAction way:
This method is invoked right before an action is to be executed (after all possible filters.) You may override this method to do last-minute preparation for the action.
Sample:
class SomeController extends Controller {
// ... other code ...
protected function beforeAction($action) {
if (parent::beforeAction($action)){
// do stuff
return true; // this line is important to let the action continue
}
return false;
}
// ... other code ...
}
As a side note, you can access the current action within a controller this way also : $this->action , to get the value of id: $this->action->id:
if($this->action->id == 'view') { // say you want to detect actionView
$this->layout = 'path/to/layout'; // say you want to set a different layout for actionView
}
Add this in the beginning of urlManager rules in the config:
'article/*' => 'article',
Your rules will have to be similar to the following :-
'rules' => array(
'<controller:\w+>/<action:\w+>' => '<controller>/<action>',
'<controller:\w+>/<action:\w+>' => 'article/index',
),
This will pass all requests to the actionIndex function in the ArticleControllerPHP Class if the Controller and/or Action does not exist.
I'm guessing you just wanna throw in a bunch of static pages in your "view" folder and have them selected and rendered automatically without adding an action for each of them in your controller.
The above suggested filters() and beforeAction() and even __construct() do not work for this purpose (filters and beforeaction do not fire up at all if the action does not exist, and __construct is very messy because if you put your functionality in __construct - at that point Yii doesnt even know which controller/action/view it should call)
however, there is a simple workaround which involves URL manager
in your config, in URL manager's rules, add one of the following lines (depending on your path settings)
'articles/<action:\w+>' => 'articles/index/action/<action>',
OR
'articles/<action:\w+>' => 'articles/index?action=<action>',
and then, in your articles controller just put up this (or similar) index action
public function actionIndex() {
$name = Yii::app()->request->getParam('action');
$this->render($name);
}
then you can call pages like /articles/myarticle or /articles/yourarticle without putting up any function in your controller. All you would need to do is just add a file named myarticle.php or yourarticle.php in your views/articles folder, and type your html content inside those files.

CakePHP: using Security::allowedControllers and Security::allowedActions

I'm trying to use Security::allowedControllers and Security::allowedActions. So I have a controller which look more or less like this
class AppController extends Controller {
var $components = array('Security'); //other components
//other stuff
}
class BookController extends AppController {
function beforeFilter() {
parent::beforeFilter();
$this->Security->allowedControllers = array('Users');
$this->Security->allowedActions = array('view');
$this->Security->RequireAuth = array('search', 'results');
}
//other stuff
}
The action 'search' displays a form, which then calls 'results' to show the results of the search. I am intentionally trying to be blackholed.
For what I understand of $this->Security->allowedControllers and $this->Security->allowedActions, I should be able to get POST data only from the action 'view' of the controller 'Users'. In particular the action 'results' should redirect me to a black hole, since it obtains POST data from the action 'search' of the controller 'Books'.
But this is not the case. I can even make cross controller requests, and never get blackholed, so I guess I'm not using correctly this variables. What is the right way to trigger cross-controller requests control?
Try this:
$this->Security->allowedFields = array('Model.fieldname', ...);
You need to add the fields that are not in the model to the allowedFields like I guess your Model.search field in the form.
This is a good and short tutorial for doing Auth with CakePHP 1.3: http://tv.cakephp.org/video/jasonwydro/2011/01/29/cakephp_1_3_auth_authentication_component_tutorial_-_administrator_login

Making a controller for home page

Can you tell me how to use a controller for home page because i'm trying to put a model's data in home.ctp (homepage view) with
<?php $this->user->find() ?>but it returns
Notice (8): Undefined property:
View::$user [APP\views\pages\home.ctp,
line 1]
You should check out the cookbook; it has some solid CakePHP tutorials, at http://book.cakephp.org/
You haven't really provided alot of information, but my guess is your Controller uses a model 'User', and you're putting $this->user->find() in your view, when it should be in your controller. In your controller's action you'll want/need to do something like this...
Users_Controller extends AppController {
function index() {
$arrayOfUsers = $this->User->find(...);
$this->set('users', $arrayOfUsers);
}
}
You can then - in your View - access 'users' like so:
pre($users);
... since you used the Controller method set() to send a variable $users to the view.
All you really need to do is create a new controller if that's the direction you want to go. If this is the only statement you have that requires data access, it might be worth faking it in only this method of the PagesController. For example, one of my projects' homepages is 99% static save for a list of featured events. Rather than move everything out to a new controller or even loading my Event model for the entire PagesController (where it's not needed), I just applied this solution in PagesController::home():
$attractions = ClassRegistry::init ( 'Attraction' )->featured ( 10 );
Works great. If your page is more dynamic than mine, though, it may well be worth routing your homepage through a different controller (one that is more closely related to the data being displayed).
The default controller for the home page i.e home.ctp view, is located in /cake/libs/controller/pages_controller.php. This controller can be overriden by placing a copy in the controllers directory of your application as /app/controllers/pages_controller.php. You can then modify that controller as deem fit i.e. use models, inject variables to be used in the home page etc

Categories