Yii call CButtonColumn from other widget - yii

i have created new widget to display information in admin view. Final view must be same as CGridView, but with different logic for columns. Everything works fine, except when i try to call CButtonColumn column.
foreach ($this->columns as $column) {
if (is_array($column) && isset($column['class']) {
$this->renderColumnWidget($column);
}
}
/* ... */
protected function renderColumnWidget($column)
{
$widgetClass = $column->class;
unset($column->class);
if (strpos($widgetClass, '.') === false) {
$widgetClass = 'zii.widgets.grid.'.$widgetClass;
}
$this->widget($widgetClass, $column); // Error from here
}
So basically here i check if there is class attribute in column and call that widget. But i get error: CButtonColumn and its behaviors do not have a method or closure named "run".
What am i doing wrong? CButtonColumn don't have run method, and i don't want to extend this class.

You this as a function like this to initiate your columns
protected function initColumns(){
foreach($this->columns as $i=>$column) {
if(is_string($column))
$column=$this->createDataColumn($column);
else {
if(!isset($column['class']))
$column['class']='CDataColumn';
$column=Yii::createComponent($column, $this);
}
if($column->id===null)
$column->id=$id.'_c'.$i;
$this->columns[$i]=$column;
}
foreach($this->columns as $column)
$column->init();
}

Related

How to check permissions in my controller

I'm new to Laravel and I'm writing a user management System on my own.
At this time,
I can CRUD permissions, roles and users,
I can check the permissions by the AuthServiceProvider#boot method like this:
public function boot()
{
Gate::before( function (User $user , $permission) {
// App administrator
if($user->getPermissions()->contains('appAll'))
{
return true;
}
// Permission check
return $user->getPermissions()->contains($permission);
});
}
In my AdminUserController, I can check the permissions like that:
public function index()
{
if( Gate::check('createUser') || Gate::check('readUser') || Gate::check('updateUser') || Gate::check('deleteUser')) {
return view('userMgmt/users/index', [
'users' => User::getUsersWithRolesWithTexts()
]);
}
else
{
return redirect(route('home'))->withErrors('You do not have required permission');
}
}
That is working well.
BUT
Is this the right way to wrap each controller method with:
if( Gate::check(...) ...) {
//Do what the method is supposed to do
}
else
{
return redirect(route('SOME.ROUTE'))->withErrors('SOME ERROR OCCURRED');
}
It would be nice if someone can give me some ideas.
Tank you
There is a controller helper function named authorize that you can call from any method in a controller that extends App\Http\Controllers\Controller. This method accepts the action name and the model, and it will throw an exception if the user is not authorized. So instead of the if...else statement, it will be one line:
public function update(Request $request, Post $post)
{
$this->authorize('update', $post);
// The current user can update the blog post...
}

how to like value to %field_value% in sql or codeigniter?

I have a table named uri_table that contain:
id, uri_segment
1, /dir_name/bla-bla-1/
2, /dir_name/bla-bla-2/
3, /dir_name/bla-bla-3/
I want to get the pure link that only contain until controller_name and the controller param are not included. but when I use $_SERVER['URI_SEGMENT'] it will get the controller param too.
so I can't do this code below to search in my model:
function check_uri()
{
$this->db->like('uri_segment',$uri_segment,'after');
$id = $this->db->get('uri_table')->row_array()['id'];
return $id;
}
instead of:
function check_uri($request_uri=$_SERVER['URI_SEGMENT'])
{
//trim controller param that is numeric
for($i = strlen($request_uri)-1;$i > 0;$i--)
{
if(is_numeric($request_uri[$i]) || $request_uri[$i]=='/')
{
continue;
}
else
{
$request_uri = substr($request_uri,0,$i+1);
break;
}
}
$this->db->where('uri_segment',$request_uri);
$id = $this->db->get('uri_table')->row_array()['id'];
return $id;
}
This is my code right now but is also can remove param that is number if the $request_uri = '/dir_name/bla-bla-3/1/some_param/3' it'll return $id null. What can I do to remove the param/get uri without controller param or how to compare the $uri_segment to uri_segment ($this->db->like($uri_segment, '%uri_segment%'))?
Do one thing when you create a controller in that store the controller name like this:
class About extends CI_Controller {
// MVC config
var $PANEL = '';
var $CONTROLLER = 'about';
var $MODEL = 'mdl_about';
var $TITLE = 'page title';
var $LIST_PAGE_NAME = 'aboutus';
function About() {
parent::__construct();
//$this->load->model($this->MODEL, 'model');
}
function index() {
$this->load->view($this->LIST_PAGE_NAME);
}
}
So that above controller, model, page title and view page can be use anywhere is related to that controller.
To display the variable value use like this:
echo $this->CONTROLLER;
Or you can try this:
$this->router->fetch_class(); //for controller
$this->router->fetch_method(); //for method

Prestashop hookActionCartSave function run 2 times?

I created a presta module and use the actionCartSave hook.
But when I print string in hookActionCartSave function, it display double result
I dont know why, can you explain for me that?
My code:
public function hookActionCartSave()
{
if (!$this->active || !Validate::isLoadedObject($this->context->cart) || !Tools::getIsset('id_product')) return;
print_r('expression');
}
The result is:
expressionexpression
Thank you
The hook ActionCartSave is called in add and update method of Cart class.
public function add($autodate = true, $null_values = false)
{
/* ... */
Hook::exec('actionCartSave');
return $return;
}
public function update($null_values = false)
{
/* ... */
Hook::exec('actionCartSave');
return $return;
}
So if you search in various controller you discover that the cart is saved more times, so the hook is called more of one times :)

Laravel Testing Error

I just started with learning how to test within Laravel. I came across some problems though..
I'm testing my controller and want to check if a View has a variable assigned.
My controller code:
class PagesController extends \BaseController {
protected $post;
public function __construct(Post $post) {
$this->post = $post;
}
public function index() {
$posts = $this->post->all();
return View::make('hello', ['posts' => $posts]);
}
}
And my view contains a foreach loop to display all posts:
#foreach ($posts as $post)
{{post->id}}
#endforeach
Last but not least my test file:
class PostControllerTest extends TestCase {
public function __construct()
{
// We have no interest in testing Eloquent
$this->mock = Mockery::mock('Eloquent', 'Post');
}
public function tearDown()
{
Mockery::close();
}
public function testIndex() {
$this->mock->shouldReceive('all')->once()->andReturn('foo');
$this->app->instance('Post', $this->mock);
$this->call('GET', '/');
$this->assertViewHas('posts');
}
}
Now comes the problem, when I run "phpunit" the following error appears:
ErrorException: Invalid argument supplied for foreach()
Any ideas why phpunit returns this error?
Your problem is here:
$this->mock->shouldReceive('all')->once()->andReturn('foo');
$this->post->all() (which is what you're mocking) should return an array, and that's what your view expects. You're returning a string.
$this->mock->shouldReceive('all')->once()->andReturn(array('foo'));
should take care of the error you have, though you'll then get an error of the "Getting property of non-object" type.
You could do this:
$mockPost = new stdClass();
$mockPost->id = 1;
$this->mock->shouldReceive('all')->once()->andReturn(array($mockpost));
You should mock the view as well:
public function testIndex() {
$this->mock->shouldReceive('all')->once()->andReturn('foo');
$this->app->instance('Post', $this->mock);
View::shouldReceive('make')->with('hello', array('posts', 'foo'))->once();
$this->call('GET', '/');
}

How to set default action dynamically in Yii

i want to change default action of a controller depends on which user is logged in.
Ex. There are two users in my site : publisher and author and i want to set publisher action as default action when a publisher is logged in, and same for author.
what should i do? when can I check my roles and set their relevant actions?
Another way to do this would be setting the defaultAction property in your controller's init() method. Somewhat like this:
<?php
class MyAwesomeController extends Controller{ // or extends CController depending on your code
public function init(){
parent::init(); // no need for this call if you don't have anything in your parent init()
if(array_key_exists('RolePublisher', Yii::app()->authManager->getRoles(Yii::app()->user->id)))
$this->defaultAction='publisher'; // name of your action
else if (array_key_exists('RoleAuthor', Yii::app()->authManager->getRoles(Yii::app()->user->id)))
$this->defaultAction='author'; // name of your action
}
// ... rest of your code
}
?>
Check out CAuthManager's getRoles(), to see that the returned array will have format of 'role'=>CAuthItem object, which is why i'm checking with array_key_exists().
Incase you don't know, the action name will be only the name without the action part, for example if you have public function actionPublisher(){...} then action name should be: publisher.
Another, simpler, thing you can do is keep the default action the same, but that default action simply calls an additional action function depending on what kind of user is logged in. So for example you have the indexAction function conditionally calling this->userAction or this->publisherAction depending on the check for who is logged in.
I think you can save "first user page" in user table. And when a user is authenticated, you can load this page from database. Where you can do this? I think best place is UserIdentity class. After that, you could get this value in SiteController::actionLogin();
You can get or set "first page" value:
if (null === $user->first_page) {
$firstPage = 'site/index';
} else {
$firstPage = $user->first_page;
}
This is a complete class:
class UserIdentity extends CUserIdentity
{
private $_id;
public function authenticate()
{
$user = User::model()->findByAttributes(array('username' => $this->username));
if ($user === null) {
$this->errorCode = self::ERROR_USERNAME_INVALID;
} else if ($user->password !== $user->encrypt($this->password)) {
$this->errorCode = self::ERROR_PASSWORD_INVALID;
} else {
$this->_id = $user->id;
if (null === $user->first_page) {
$firstPage = 'site/index';
} else {
$firstPage = $user->first_page;
}
$this->errorCode = self::ERROR_NONE;
}
return !$this->errorCode;
}
public function getId()
{
return $this->_id;
}
}
/**
* Displays the login page
*/
public function actionLogin()
{
$model = new LoginForm;
// if it is ajax validation request
if (isset($_POST['ajax']) && $_POST['ajax'] === 'login-form') {
echo CActiveForm::validate($model);
Yii::app()->end();
}
// collect user input data
if (isset($_POST['LoginForm'])) {
$model->attributes = $_POST['LoginForm'];
// validate user input and redirect to the previous page if valid
if ($model->validate() && $model->login())
$this->redirect(Yii::app()->user->first_page);
}
// display the login form
$this->render('login', array('model' => $model));
}
Also, you can just write right code only in this file. In SiteController file.