set some view variable in controller constructer - zend-view

I have the following code in my zf2 controller:
<?php
namespace Accounting\Controller;
use Zend\Mvc\Controller\ActionController,
Zend\View\Model\ViewModel,
Accounting\Model,
Zend\Paginator,
Accounting\Scripts\CMSTranslator;
class AdminController extends ActionController {
protected $translator;
public function setTranslator(CMSTranslator $translator) {
$this->translator = $translator;
return $this;
}
public function __construct(\Doctrine\ORM\EntityManager $em,CMSTranslator $translator) {
$this->em = $em;
//$this->translator = new \Zend\Translator\Translator('ArrayAdapter', __DIR__ . '/../../../lang/lang-fa.php', 'fa');
$this->translator = $translator;
\Zend\Registry::set('tr', $this->translator);
// now you can use the EntityManager!
}
As you can see I'm using the zend\translator module.
I want to add it to the view in my controller constructor.
I already tried:
return ViewModel(array('tr'=>$translator));
But that doesn't work.
Please help.

add a private class variable private $viewModel. Then create the ViewModel in your construtor, add any variables:
$this->viewModel = new ViewModel();
$this->viewModel->tr = $translator;
Then return $this->viewModel from your action function.

Final solution module.config.php
'Accounting\Controller\AccountingController' => array(
'parameters' => array(
'em' => 'doctrine_em',
'translator' => 'Accounting\Scripts\CMSTranslator',
),
),
'Zend\View\Helper\Translator' => array(
'parameters' => array(
'translator' => 'Accounting\Scripts\CMSTranslator'
)
),
'Accounting\Scripts\CMSTranslator' => array(
'parameters' => array(
'options' => array('adapter' => 'ArrayAdapter', 'content' => __DIR__ . '/../lang/lang-fa.php', 'local' => 'fa')
)
),
'translateAdapter' => array(
'parameters' => array(
'options' => array('adapter' => 'ArrayAdapter', 'content' => __DIR__ . '/../lang/lang-fa.php', 'local' => 'fa')
)
),

Related

zfcuser + doctrine custom user entity

I'm working on a project with zf2, and the zfcuser module with doctrine. I have created a custom user module that extends zfcuser, also a custom entity for the user table, and make all the necessary changes for the integration. But my problem is when trying to authenticate myself, I get this error:
An alias "Zend\Db\Adapter\Adapter" was requested but no service could be found.
This happens when zfcuser_user_mapper attempts to change the adapter.
Note: I am not very clear why I need to use the Zend \ Db \ Adapter \ Adapter, since I am working with doctrine.
This is the code in the module.php of the custom user module.
public function getServiceConfig() {
return [
'aliases' => array(
'zfcuser_zend_db_adapter' => 'Zend\Db\Adapter\Adapter',
),
'factories' => [
'usuario_login_form' => 'Usuario\Factory\Form\Login',
'usuario_registro_form' => 'Usuario\Factory\Form\Register',
'usuario_user_service' => 'Usuario\Factory\Service\UserFactory',
//'usuario_user_mapper' => 'Usuario\Factory\Mapper\User',
'usuario_auth_service' => 'Usuario\Factory\AuthenticationService',
'Usuario\Authentication\Adapter\Db' => 'Usuario\Factory\Authentication\Adapter\DbFactory',
'Usuario\Authentication\Storage\Db' => 'Usuario\Factory\Authentication\Storage\DbFactory',
//'Zend\Db\Adapter\Adapter' => 'Zend\Db\Adapter\Adapter',
'usuario_user_mapper' => function ($sm) {
$mapper = new Mapper\User();
$mapper->setDbAdapter($sm->get('zfcuser_zend_db_adapter'));
$mapper->setEntityPrototype(new ORM\Entity\Usuarios());
$mapper->setHydrator(new \ZfcUser\Mapper\UserHydrator());
return $mapper;
},
]
];
}
This is my global.php file
return array(
'doctrine' => array(
'connection' => array(
'orm_default' => array(
'driverClass' => 'Doctrine\DBAL\Driver\PDOMySql\Driver',
'params' => array(
'host' => 'localhost',
'port' => '3306',
'user' => 'root',
'password' => 'toor',
'dbname' => 'deporte',
)
)
)
),
);
This is my module.config.php file:
'controllers' => array(
),
'doctrine' => array(
'driver' => array(
// overriding zfc-user-doctrine-orm's config
'usuario_entity' => array(
'class' => 'Doctrine\ORM\Mapping\Driver\AnnotationDriver',
'paths' => __DIR__ . '/../src/Usuario/ORM/Entity',
),
'orm_default' => array(
'drivers' => array(
'Usuario\ORM\Entity' => 'usuario_entity',
),
),
),
),
'zfcuser' => array(
'auth_adapters' => array(100 => 'Usuario\Authentication\Adapter\Db'),
// telling ZfcUser to use our own class
'user_entity_class' => 'Usuario\ORM\Entity\Usuarios',
// telling ZfcUserDoctrineORM to skip the entities it defines
'enable_default_entities' => false,
),
I thank you for the help, I have already been with this error for days. Thank you very much, and excuse my English.
If you want to change the Entity and want to use your then use following steps:
if the zfcuser.global.php file which is placed in config/autoload folder (if not then you can copy if from zfcuser module.
In this global file search for "user_entity_class" key and define your own entity class.By default it uses
'user_entity_class' => 'ZfcUser\Entity\User',
Like I am using it for Employee entity
'user_entity_class' => 'Employee\Entity\Employee',
In this entity you need to implement UserInterface.
use ZfcUser\Entity\UserInterface;
/**
* Employee
*
* #ORM\Table(name="employee")
* #ORM\Entity(repositoryClass="Employee\Repository\EmployeeRepository")
*/
class Employee implements UserInterface {
}
If you want to override db adapter then you need to do following steps:
'service_manager' => array(
'invokables' => array(
'ZfcUser\Authentication\Adapter\Db' => 'Employee\Authentication\Adapter\Db',
),
),
In this file you need to extend and implements.
namespace Employee\Authentication\Adapter;
use InvalidArgumentException;
use Zend\Authentication\Result as AuthenticationResult;
use Zend\Crypt\Password\Bcrypt;
use Zend\ServiceManager\ServiceManager;
use Zend\ServiceManager\ServiceManagerAwareInterface;
use Zend\Session\Container as SessionContainer;
use ZfcUser\Authentication\Adapter\AdapterChainEvent as AuthenticationEvent;
use ZfcUser\Entity\UserInterface as UserEntity;
use ZfcUser\Mapper\HydratorInterface as Hydrator;
use ZfcUser\Mapper\UserInterface as UserMapper;
use ZfcUser\Authentication\Adapter\AbstractAdapter;
use ZfcUser\Options\AuthenticationOptionsInterface as AuthenticationOptions;
class Db extends AbstractAdapter implements ServiceManagerAwareInterface
{
}
For more information you can follow zfcuser wiki here:
https://github.com/ZF-Commons/ZfcUser/wiki

is_user_logged_in() return false even when logged in to WordPress?

I have a plugin that I created and I want to use the WP rest api controller pattern and extend the api.
<?php
/**
* Plugin Name: myplugin
* Plugin URI: h...
* Description: A simple plugin ...
* Version: 0.1
* Author: Kamran ...
* Author ....
* License: GPL2
function myplugin_register_endpoints(){
require_once 'server/controllers/my_ctrl.php';
$items=new items();
$items->register_routes();
}
add_action('rest_api_init','myplugin_register_endpoints');
.
.
I created a class in folder called server/controllers and inside it my_ctrl.php file with a class that extends WP_REST_Controller that looks like this
<?php
class items extends WP_REST_Controller {
/**
* Register the routes for the objects of the controller.
*/
public function register_routes() {
$version = '1';
$namespace = 'my-namespase/v' . $version;
$base = 'abc';
register_rest_route( $namespace, '/' . $base, array(
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'get_items' ),
'permission_callback' => array( $this, 'get_items_permissions_check' ),
'args' => array(
'id' => array(
'required' => true,
'validate_callback' => function($param, $request, $key) {
return is_numeric( $param ) and ! is_null(get_post($param));//numeric post id value and there is valid post for this id
},
'sanitize_calback' => 'absint'
)
),
),
) );
register_rest_route( $namespace, '/' . $base . '/(?P<id>[\d]+)', array(
array(
'methods' => WP_REST_Server::CREATABLE,
'callback' => array( $this, 'create_item' ),
'permission_callback' => array( $this, 'create_item_permissions_check' ),
'args' => array(
'id' => array(
'required' => true,
'validate_callback' => function($param, $request, $key) {
return is_numeric( $param ) and ! is_null(get_post($param));//numeric post id value and there is valid post for this id
},
'sanitize_calback' => 'absint'
)
),
),
array(
'methods' => WP_REST_Server::DELETABLE,
'callback' => array( $this, 'delete_item' ),
'permission_callback' => array( $this, 'delete_item_permissions_check' ),
'args' => array(
'id' => array(
'required' => true,
'validate_callback' => function($param, $request, $key) {
return is_numeric( $param ) and ! is_null(get_post($param));//numeric post id value and there is valid post for this id
},
'sanitize_calback' => 'absint'
)
),
),
) );
register_rest_route( $namespace, '/' . $base . '/schema', array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'get_public_item_schema' ),
) );
}
function get_items( $request ){
return new WP_REST_Response( array('message' => "list items"), 200 );
}
function create_item( $request ) {
.....
if($author_email==$user_email) {
return new WP_REST_Response( array('message' => 'success', 200 );
} else {
return new WP_Error('my-error', __(' error...','abc'), array( 'status' => 500 ));
}
}
//Remove vote////////////////////////////////////////////
function delete_item( $request ) {
...
if($author_email==$user_email) {
return new WP_REST_Response( array('message' => 'success', 200 );
} else {
return new WP_Error('my-error', __(' error...','abc'), array( 'status' => 500 ));
}
}
public function get_items_permissions_check( $request ) {
return true;
}
public function create_item_permissions_check( $request ) {
if ( !is_user_logged_in()) {
return new WP_Error('login error',__('You are not logged in','KVotes-voting'));
}
return true;
}
public function delete_item_permissions_check( $request ) {
return $this->create_item_permissions_check( $request );
}
protected function prepare_item_for_database( $request ) {
return array();
}
public function prepare_item_for_response( $item, $request ) {
return array();
}
public function get_collection_params() {
return array(
'page' => array(
'description' => 'Current page of the collection.',
'type' => 'integer',
'default' => 1,
'sanitize_callback' => 'absint',
),
'per_page' => array(
'description' => 'Maximum number of items to be returned in result set.',
'type' => 'integer',
'default' => 10,
'sanitize_callback' => 'absint',
),
'search' => array(
'description' => 'Limit results to those matching a string.',
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
),
);
}
}
I am logged in and I am using cookie authentication with Nonce in my plugin.
when I run my code and debug it with sublime xdebug extension I can see that I indeed hit the end points routes but although I am logged it in the lines: "is_user_logged_in()" = (bool) 0 and therefore the function create_item_permissions_check return new WP_Error(....);and not true;
therefore my rest callback "create_item" is not invoked, I don't understand why is_user_logged_in() return false even when I am logged in.
The solution was to send the logged in user info to my custom class as a parameter to the constructor and then use the user data in the permission check function and other functions that needs the user info:
class items extends WP_REST_Controller {
/**
* Register the routes for the objects of the controller.
*/
private $loged_in;//bool
private $user;
public function __construct($logged,$cur_user) {
= $logged;
$this->user = $cur_user;
}
.
.
.
public function create_item_permissions_check( $request ) {
if($this->loged_in!=1){
return new WP_Error('login error',__('You are not logged in','....'));
}
return true;
}
.
.
.
}
And my plugin myplugin_register_endpoints looks as follows:
function myplugin_register_endpoints(){
require_once 'server/controllers/my_ctrl.php';
$items=new items(is_user_logged_in(),wp_get_current_user());
$items->register_routes();
}
now when I route to one of the URL's And hit the end points and the check permission is invoked with the needed user data. $this->loged_in!=1 when thew user is not logged in, otherwise the permission check returns true .
I ran into precisely this issue. It seems that the architecturally correct way to handle the problem is for the ajax request to include a nonce. See the references discussed in this answer

Nested Whgridview. Grids disappear on sort or pagination click

I'm a newbie in Yii programming.
I'm using boostrap library on Yii via Yiistrap/Yiiwheels
I've created a relation table view
The related view is a Whgridview itself
The first (master grid) has a TbRelationColum clicking it i display the second grid (detail grid).
When I click on the row to display the sub grid, everything appears ok. When I change the sort order or the page of the sub grid disappear both grid.
I understand we should differentiate the css class of the pager and the sort of sub grid from the main grid. How to do this specifically in Yii-Way?
Is This the problem?
This is the view of the main grid:
$this->widget('yiiwheels.widgets.grid.WhGridView',array(
'id'=>'masterGrid',
'dataProvider'=>$model->search(),
'filter'=>$model,
'template' => "{summary}{items}<div class=\"row-fluid\"><div class=\"pull-right\">{pager}</div></div>",
'type' => array(TbHtml::GRID_TYPE_BORDERED, TbHtml::GRID_TYPE_STRIPED),
'columns'=>array(
array(
'class' => 'yiiwheels.widgets.grid.WhRelationalColumn',
//'name' => 'multiMembers.id',
'type' => 'raw',
'header' => 'Sub Items',
'url' => $this->createUrl('multiGroup/ajaxSubItems'),
'cacheData' => false,
'value' => "CHtml::tag('button',array('class'=>'btn btn-primary'),'Sub Items')",
'htmlOptions'=>array('style'=>'width:90px;'),
'cssClass' => 'showSubItems',
),
'id',
'title',
array(
'class'=>'bootstrap.widgets.TbButtonColumn',
),
),
));
This is the sub-grid:
echo CHtml::tag('h3',array(),'Sub Items Group #"'.$id.'"');
$this->widget('yiiwheels.widgets.grid.WhGridView', array(
'id'=>'subGrid_'.$id,
'type'=>array(TbHtml::GRID_TYPE_BORDERED, TbHtml::GRID_TYPE_STRIPED),
'dataProvider' => $gridDataProvider,
'template' => "{summary}{items}<div class=\"row-fluid\"><div class=\"pull-right\">{pager}</div></div>",
'columns' => $gridColumns,
));
This is the controller:
/**
* Manages all models.
*/
public function actionAdmin()
{
$model=new MultiGroup('search');
$model->unsetAttributes(); // clear any default values
if (isset($_GET['MultiGroup'])) {
$model->attributes=$_GET['MultiGroup'];
}
$this->render('admin',array(
'model'=>$model,
));
}
public function actionAjaxSubItems()
{
$id = Yii::app()->getRequest()->getParam('id');
$model = $this->loadModel($id);
if($model->numSubItems > 0) {
$this->renderPartial('_child', array('id' => $id,
'gridDataProvider' => $this->getGridDataProvider($id),
'gridColumns' => $this->getGridColumns()
), false, true);
} else {
echo 'Non ci sono Sub Items.';
}
}
public function getGridDataProvider($id) {
$sql = 'SELECT * FROM multi_member WHERE groupid = :groupid ORDER BY lastname,firstname';
$cmd = Yii::app()->db->createCommand($sql);
$cmd->bindParam(':groupid', $id, PDO::PARAM_INT);
$result = $cmd->queryAll();
$dataProvider = new CArrayDataProvider(
$result, array(
'sort' => array(
'attributes' => array('id','groupid','firstname','lastname','membersince'),
'defaultOrder' => array('lastname' => CSort::SORT_ASC, 'firstname' => CSort::SORT_ASC),
),
'pagination' => array(
'pageSize' => 2,
),
));
return $dataProvider;
}
public function getGridColumns() {
return array('id', 'lastname', 'firstname', 'membersince');
}
How can I do?
thank you ..
If the extensions you're using all extend CGgridView, then you should be able to use option 'ajaxUpdate' (link to documentation).
Try setting 'ajaxUpdate'=>false in one of the grids (or in both of them) to see whether it helps you.
Sometimes setting ajaxUpdate to false is the only way I get get some grids to behave the way I want them to...

How can I use yii widget nested another widget?

class CommonHeaderWidget extends CWidget {
public function run() {
// I want use Another widget here,
// but it's no use like this:
$this->getController->widget('bootstrap.widgets.TbNavbar', array(
'items' => array(
array(
'class' => 'bootstrap.widgets.TbMenu',
'items' => array(
array('label' => 'mall', 'url' => '#'),
array('label' => 'Join', 'url' => #),
),
),
),
));
// end.
$this->render('commonHeader');
}
}
Then,I put the widget TbNavbar in commonHeader view ,it's no use too! How can I do?

ZF2: create url aliases in router

I'm new to Zend Framework 2 and i want to learn this framework. I want to create url aliases in router.
For example, I have defined something like this in module.config.php
'router' => array(
'routes' => array(
'home' => array(
'type' => 'Zend\Mvc\Router\Http\Literal',
'options' => array(
'route' => '/',
'defaults' => array(
'controller' => 'Application\Controller\Index',
'action' => 'index',
),
),
),
'node' => array(
'type' => 'Application\Controller\AliasSegment',
'options' => array(
'route' => '/node[/:id]',
'constraints' => array(
'id' => '[0-9]+'
),
'defaults' => array(
'__NAMESPACE__' => 'Application\Controller',
'controller' => 'Index',
'action' => 'index',
'id' => '0'
),
),
'may_terminate' => true,
),
),
),
When i type www.myapp.local/node/1 it routes to the default action in default controller of my application. What i want is a router extension that can handle aliases for url paths. For example:
www.myapp.local/node/1 = www.myapp.local/aboutus
www.myapp.local/node/2 = www.myapp.local/company/gallery
I know that it was possible in ZF. Here is a link to tutorial how to achieve this in ZF:
friendly urls
I know that this is in Polish but code is self-explanatory i think :)
The idea is to use url helper to assembly valid url using aliases or normal segments (node/[:id])
I've already created AliasSegment class in my Application\Controller folder but it shows me an error:
Fatal error: Uncaught exception 'Zend\ServiceManager\Exception\ServiceNotFoundException' with message 'Zend\ServiceManager\ServiceManager::get was unable to fetch or create an instance for Application\Controller\AliasSegment' in C:\xampp\htdocs\industengine\vendor\zendframework\zendframework\library\Zend\ServiceManager\ServiceManager.php:450 Stack trace: #0
My AliasSegment class (incomplete):
<?php
namespace Zend\Mvc\Router\Http;
use Traversable;
use Zend\Mvc\Router\Exception;
use Zend\Stdlib\ArrayUtils;
use Zend\Stdlib\RequestInterface as Request;
class AliasSegment extends Segment
{
public function match(Request $request, $pathOffset = null)
{
}
}
I was looking for an answer for hours and i couldnt find anything. Please tell me at least what I'm doing wrong, where to insert a code or maybe You know better sollution?
I'm not looking for ready application. I want to learn something but i would appreciate if You can tell me an answer in details :)
Thanks in advance and sorry for my English :)
EDITED:
My custom router is working now. At this moment aliases are hardcoded but it works.
My AliasSegment class looks now:
<?php
namespace Application\Controller;
use Traversable;
use Zend\Mvc\Router\Exception;
use Zend\Stdlib\ArrayUtils;
use Zend\Stdlib\RequestInterface as Request;
use Zend\Mvc\Router\Http;
class AliasSegment extends \Zend\Mvc\Router\Http\Segment
{
public function match(Request $request, $pathOffset = null)
{
$uri = $request->getUri();
$path = $uri->getPath();
//sample logic here
//for /about/gallery uri set node id to 1
//todo: get action, controller and module from navigation
if($path == '/about/gallery'){
$uri->setPath('/node/1');
$request->setUri($uri);
}
return parent::match($request, $pathOffset);
}
protected function buildPath(array $parts, array $mergedParams, $isOptional, $hasChild)
{
if(isset($mergedParams['link'])){
return $mergedParams['link'];
}
return parent::buildPath($parts, $mergedParams, $isOptional, $hasChild);
}
}
In this case /about/gallery is an alias to /node/1. Both adresses are correct. The buildPath function returns alias path correctly. Well, I hope this would be usefull for somebody :)
However i want to setup it in Zend_Navigation with additional parameter named 'link'.
I've done 50% of what i want to achieve however now I have problem to get Zend_Navigation from my router. I don't know how to pass it. I guess it should be something like this:
$sm = $this->getServiceLocator();
$auth = $sm->get('Navigation');
It works in my IndexController but doesnt work in my AliasSegment. I need to find in navigation array nodes with 'link' parameter.
EDIT
I've found solution. The answer is below.
unable to fetch or create an instance for Application\Controller\AliasSegment
if this is controller then I would expect in module.config.php to have:
'controllers' => array(
'invokables' => array(
'\Application\Controller\AliasSegment' => '\Application\Controller\AliasSegment',
)
),
also namespace of your class looks a bit weird:
namespace Zend\Mvc\Router\Http;
what about:
namespace Application\Controller;
OK, I've made it. The important thing for this Thread:
ZF2: How to get Zend\Navigation inside custom route?.
You can use any segment type route. But this may need a little modifications to match function.
If navigation's single page will have 'link' param, the url will be converted to 'link' string but other params will stay behind it. Just think of it as an overlay for default URI of current route.
I had to modify my custom route class a little bit. First of all, i had to change its namespace to Application\Router. Here is a full class:
// EDIT - file within ModuleName/src/Router/Alias.php
namespace Application\Router;
use Traversable;
use Zend\Mvc\Router\Exception;
use Zend\Stdlib\ArrayUtils;
use Zend\Stdlib\RequestInterface as Request;
use Zend\Mvc\Router\Http;
class Alias extends Http\Segment
{
private static $_navigation = null;
public function match(Request $request, $pathOffset = null)
{
$uri = $request->getUri();
$path = $uri->getPath();
$items = self::$_navigation->findAllBy('route', 'node');
$params = null;
if($items != null){
$t = sizeof($items);
for ($i=0; $i < $t; $i++) {
$item = $items[$i];
$params = $item->getParams();
if (isset($params['link']) && $params['link']==$path){
$uri->setPath('/'.$item->getRoute().'/'.$params['id']);
$request->setUri($uri);
break;
}
}
}
return parent::match($request, $pathOffset);
}
public function setNavigation($navigation){
self::$_navigation = $navigation;
}
protected function buildPath(array $parts,
array $mergedParams, $isOptional, $hasChild)
{
if(isset($mergedParams['link'])){
return $mergedParams['link'];
}
return parent::buildPath($parts, $mergedParams,
$isOptional, $hasChild);
}
}
here is sample part of module.config.php:
'navigation' => array(
// The DefaultNavigationFactory we configured in (1) uses 'default' as the sitemap key
'default' => array(
// And finally, here is where we define our page hierarchy
'account' => array(
'label' => 'Account',
'route' => 'node',
'params' => array(
'id' => '2',
),
'pages' => array(
'home' => array(
'label' => 'Dashboard',
'route' => 'node',
'params' => array(
'id' => '8',
'link' => '/about/gallery'
),
),
'login' => array(
'label' => 'Sign In',
'route' => 'node',
'params' => array(
'id' => '6',
'link' => '/signin'
),
),
'logout' => array(
'label' => 'Sign Out',
'route' => 'node',
'params' => array(
'id' => '3',
),
),
),
),
),
),
'router' => array(
'routes' => array(
'home' => array(
'type' => 'Zend\Mvc\Router\Http\Literal',
'options' => array(
'route' => '/',
'defaults' => array(
'controller' => 'Application\Controller\Index',
'action' => 'index',
),
),
),
'node' => array(
'type' => 'Application\Router\Alias',
'options' => array(
'route' => '/node[/:id]',
'constraints' => array(
'id' => '[0-9]+'
),
'defaults' => array(
'__NAMESPACE__' => 'Application\Controller',
'controller' => 'Index',
'action' => 'index',
'id' => '0'
),
),
'may_terminate' => true,
),
),
),
If it is just for routes like /about and /about/galery then you can simply use literal routes with child routes
'about' => array(
'type' => 'literal',
'options' => array(
'route' => '/about',
'defaults' => array(
'controller' => 'module-controller-about',
'action' => 'index'
)
),
'may_terminate' => true,
'child_routes' => array(
'galery' => array(
'type' => 'literal',
'options' => array(
'route' => '/galery',
'defaults' => array(
'controller' => 'module-controller-galery'
)
)
)
)
)
When it comes to URLs like /blog/1-my-great-seo-title you probably have to set-up a Regex route (which is the slowest, literals are fastest).
Maybe check out DASPRiDs Slides from his Router Presentation