I need to call several functions from the same class in a hook file.
This is my current code:
$hook['post_controller_constructor'] = array(
'class' => 'get_info_general',
'function' => 'prepare',
'filename' => 'get_info_general.php',
'filepath' => 'hooks',
'params' => ''
);
$hook['post_controller_constructor'] = array(
'class' => 'get_info_general',
'function' => 'get_info_general',
'filename' => 'get_info_general.php',
'filepath' => 'hooks',
'params' => ''
);
$hook['post_controller_constructor'] = array(
'class' => 'get_info_general',
'function' =>'get_achievements',
'filename' => 'get_info_general.php',
'filepath' => 'hooks',
'params' => ''
);
Unfortunately only the last function get_achievements is called. I also tried:
$hook['post_controller_constructor'] = array(
'class' => 'get_info_general',
'function' => 'prepare',
'function' => 'get_info_general',
'function' => 'get_achievements',
'filename' => 'get_info_general.php',
'filepath' => 'hooks',
'params' => ''
);
But it gives me the same result.
Is there any way to get all three functions to be called correctly, one after another? I didn't find documentation or similar questions.
You just need to make multidimensional array. From docs:
If want to use the same hook point with more than one script, simply make your array declaration multi-dimensional, like this:
$hook['post_controller_constructor'][] = array(
'class' => 'get_info_general',
'function' => 'prepare',
'filename' => 'get_info_general.php',
'filepath' => 'hooks',
'params' => ''
);
$hook['post_controller_constructor'][] = array(
'class' => 'get_info_general',
'function' => 'get_info_general',
'filename' => 'get_info_general.php',
'filepath' => 'hooks',
'params' => ''
);
$hook['post_controller_constructor'][] = array(
'class' => 'get_info_general',
'function' =>'get_achievements',
'filename' => 'get_info_general.php',
'filepath' => 'hooks',
'params' => ''
);
Notice the brackets after each array index:
$hook['post_controller_constructor'][]
Related
I am having an unfourtunate bug that prevents my model from saving (a timeout happens).
I tried debugging by dumping in various places during save and it seems that call to the updating event is where it gets stuck. I do not have any event handlers bound to this event myself, but it still seems to try firing it and fails.
By dumping backtrace somewhere deep in the code I see an endless chain of toArray, relationsToArray and an occasional array_map call. It seems like the dispatcher or something is trying to serialize the model and running in a loop of relations.
Here is some of trace:
276 =>
array (
'file' => '/srv/myapp/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php',
'line' => 972,
'function' => 'relationsToArray',
'class' => 'Illuminate\\Database\\Eloquent\\Model',
'type' => '->',
),
277 =>
array (
'file' => '/srv/myapp/vendor/laravel/framework/src/Illuminate/Support/Collection.php',
'line' => 1686,
'function' => 'toArray',
'class' => 'Illuminate\\Database\\Eloquent\\Model',
'type' => '->',
),
278 =>
array (
'function' => 'Illuminate\\Support\\{closure}',
'class' => 'Illuminate\\Support\\Collection',
'type' => '->',
),
279 =>
array (
'file' => '/srv/myapp/vendor/laravel/framework/src/Illuminate/Support/Collection.php',
'line' => 1687,
'function' => 'array_map',
),
280 =>
array (
'file' => '/srv/myapp/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php',
'line' => 241,
'function' => 'toArray',
'class' => 'Illuminate\\Support\\Collection',
'type' => '->',
),
281 =>
array (
'file' => '/srv/myapp/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php',
'line' => 972,
'function' => 'relationsToArray',
'class' => 'Illuminate\\Database\\Eloquent\\Model',
'type' => '->',
),
Unfourtunately, I can't track down which relations are causing this to try and fix it. How should I debug and fix this?
In my symfony application, I use voters to check if users can access some features.
Now, I have a navbar where the menus are displayed or hidden according to those rights.
This navbar alone renders in about 2 seconds. That's a lot added to every page.
If I comment out the render_controller of the navbar, I gain 2 seconds. If I return true at the top of every voter is_granted method, I gain 1.5 seconds.
How can I solve this ? Using cache ? not using voters ? simplifying my voters ? Is it not a best practice to use voters? even if symfony has to check attributes against the list of all attributes?
My navbar generator:
<?php
namespace AppBundle\Menu;
use AppBundle\Application\Core\ExplorerManager;
use AppBundle\Entity\User\Associate;
use AppBundle\Entity\User\Role;
use Symfony\Component\Routing\Router;
use Symfony\Component\Security\Core\Authorization\AuthorizationChecker;
use Symfony\Component\Translation\Translator;
class MenuBuilder
{
/**
* #var Router
*/
private $router;
/**
* #var Translator
*/
private $translator;
/**
* #var AuthorizationChecker
*/
private $authorizationChecker;
/**
* #param Router $router
* #param Translator $translator
* #param AuthorizationChecker $authorizationChecker
*/
public function __construct(Router $router, Translator $translator, AuthorizationChecker $authorizationChecker)
{
$this->router = $router;
$this->translator = $translator;
$this->authorizationChecker = $authorizationChecker;
}
public function getFrontendHeaderMenuItems($isAuthenticated)
{
$menuItems = array(
array(
'title' => 'pricing',
'route' => 'cms',
'route_parameters' => array('dir' => 'general', 'page' => 'foodmeup_premium')
),
// array(
// 'title' => 'recipes',
// 'route' => 'explore',
// 'route_parameters' => array('object' => ExplorerManager::RECETTE)
// ),
array(
'title' => 'blog',
'route' => 'explore',
'route_parameters' => array('object' => ExplorerManager::BLOG)
),
array(
'title' => 'contact',
'route' => 'message_foodmeup'
)
);
if (false == $isAuthenticated) {
$menuItems[] = array(
'title' => 'login',
'route' => 'login'
);
}
$menuItems = $this->generateMenuRoutes(
$menuItems,
'frontend_bars',
array()
);
return $menuItems;
}
public function getBackendLeftSidebarMenuItems()
{
$menuItems = array(
array(
'title' => 'dashboard',
'icon' => 'th-large',
'route' => 'dashboard'
),
array(
'title' => 'administration',
'icon' => 'star',
'is_granted' => Role::ROLE_ADMIN,
'children' => array(
array(
'title' => 'dashboard',
'route' => 'admin_dashboard',
),
array(
'title' => 'moderation',
'route' => 'moderate_posts',
),
array(
'title' => 'users',
'route' => 'switch_user',
'is_granted' => Role::ROLE_SUPERADMIN,
),
array(
'title' => 'subscriptions',
'route' => 'grant_partner_subscription',
'is_granted' => Role::ROLE_SUPERADMIN,
)
)
), array(
'title' => 'ingredients',
'icon' => 'flask',
'children' => array(
array(
'title' => 'explore_ingredients',
'route' => 'explore',
'route_parameters' => array('object' => ExplorerManager::CONSOMMABLE)
),
array(
'title' => 'my_ingredients',
'route' => 'user_ingredients_display',
'is_granted' => Associate::READ_INGREDIENT
), array(
'title' => 'create_import',
'route' => 'edit_ingredient',
'is_granted' => Associate::EDIT_INGREDIENT
), array(
'title' => 'stock',
'route' => 'set_ingredient_stock',
'is_granted' => Associate::READ_STOCK,
), array(
'title' => "buying_cost",
'route' => 'parameter_cost',
'is_granted' => Associate::READ_COST,
)
)
), array(
'title' => 'recipes',
'icon' => 'birthday-cake',
'children' => array(
array(
'title' => 'explore_recipes',
'route' => 'explore',
'route_parameters' => array('object' => ExplorerManager::RECETTE)
),
array(
'title' => 'my_recipes',
'route' => 'user_recipes_display',
'is_granted' => Associate::READ_RECIPE
), array(
'title' => 'create',
'route' => 'edit_recipe',
'is_granted' => Associate::EDIT_RECIPE
), array(
'title' => 'print',
'route' => 'print_recipes',
'is_granted' => Associate::READ_RECIPE
)
)
), array(
'title' => 'plannings',
'icon' => 'tasks',
'is_granted' => array(Associate::READ_PLANNING, Associate::EDIT_PLANNING, Associate::DELETE_PLANNING),
'children' => array(
array(
'title' => 'my_plannings',
'route' => 'display_plannings',
'is_granted' => Associate::READ_PLANNING
), array(
'title' => 'my_models',
'route' => 'display_plannings',
'route_parameters' => array('isModel' => true),
'is_granted' => Associate::READ_PLANNING
), array(
'title' => 'create_planning',
'route' => 'edit_planning',
'is_granted' => array(Associate::EDIT_PLANNING, Associate::CREATE_MODEL)
)
)
), array(
'title' => 'orders',
'icon' => 'phone',
'is_granted' => array(Associate::READ_ORDER, Associate::EDIT_ORDER, Associate::EDIT_ORDER, Associate::DELETE_ORDER),
'children' => array(
array(
'title' => 'my_orders',
'route' => 'display_planning_orders',
'is_granted' => Associate::READ_ORDER
), array(
'title' => 'automatic_order',
'route' => 'automatic_order',
'is_granted' => Associate::EDIT_ORDER
), array(
'title' => 'edit_order',
'route' => 'edit_order',
'is_granted' => Associate::EDIT_ORDER
)
)
), array(
'title' => 'suppliers',
'icon' => 'truck',
'is_granted' => array(Associate::EDIT_SUPPLIER, Associate::READ_SUPPLIER, Associate::DELETE_SUPPLIER),
'children' => array(
array(
'title' => 'my_suppliers',
'route' => 'display_suppliers',
'is_granted' => Associate::READ_SUPPLIER
), array(
'title' => 'select',
'route' => 'user_supplier_select',
'is_granted' => Associate::EDIT_SUPPLIER
), array(
'title' => 'create',
'route' => 'edit_organization',
'route_parameters' => array('category_slug' => 'fournisseur-de-consommables'),
'is_granted' => Associate::EDIT_SUPPLIER
)
)
), array(
'title' => 'teams',
'icon' => 'users',
'is_granted' => array(Associate::EDIT_TEAM, Associate::READ_TEAM, Associate::DELETE_TEAM, Associate::MANAGE_RIGHTS),
'children' => array(
array(
'title' => 'my_teams',
'route' => 'teams_display',
), array(
'title' => 'worker_parameter',
'route' => 'worker_parameter',
'is_granted' => Associate::EDIT_TEAM,
)
)
)
);
$menuItems = $this->generateMenuRoutes($menuItems, 'backend_bars', array());
return $menuItems;
}
private function generateMenuRoutes(Array $menuItems, $domain, $isGranted)
{
foreach ($menuItems as $key => $menuItem) {
if (array_key_exists('is_granted', $menuItems[$key])) {
$rights = is_array($menuItems[$key]['is_granted']) ? $menuItems[$key]['is_granted'] : array($menuItems[$key]['is_granted']);
$rights = array_map(function ($right) {
return $this->authorizationChecker->isGranted($right);
}, $rights);
if (in_array(true, $rights) == false) {
unset($menuItems[$key]);
continue;
}
}
if (array_key_exists('route', $menuItems[$key])) {
$menuItems[$key]['uri'] = $this->router->generate($menuItems[$key]['route'], array_key_exists('route_parameters', $menuItems[$key]) ? $menuItems[$key]['route_parameters'] : array());
} else {
$menuItems[$key]['uri'] = '#/';
}
$menuItems[$key]['title'] = $this->translator->trans($menuItems[$key]['title'], array(), $domain);
if (array_key_exists('children', $menuItems[$key])) {
$menuItems[$key]['children'] = $this->generateMenuRoutes($menuItems[$key]['children'], $domain, $isGranted);
}
}
return $menuItems;
}
public function extractTitles(Array $menuItems)
{
$titles = array();
foreach ($menuItems as $key => $menuItem) {
$titles[] = $menuItems[$key]['title'];
if (array_key_exists('children', $menuItems[$key])) {
$titles = array_merge($titles, $this->extractTitles($menuItems[$key]['children']));
}
}
return $titles;
}
}
Voters have performance drawbacks. So if you need a higher performance then it's better to use ACL or optimize voters loading, because symfony loops over all voters when each security check is performed.
Lets's suppose you have 30 links in a menu and there are 20 voters. When you check access to all links in 1 loop then symfony will call voters 600 times (the most of them will return Voter::ACCESS_ABSTAIN immediately, but it still takes time and in you case it takes too much time).
Update:
Symfony added voter caching for skipping call unneeded voters if new functions supportsAttribute or supportsType returned false once.
https://symfony.com/blog/new-in-symfony-5-4-faster-security-voters
i'm new to phpunit and have read the documentation on mock objects but it isn't very clear.
I am trying to write a simple test that asserts a method within a class is called. With the following code, i am testing that when the Client::exchangeArray is called, a call is made to Client::getInputFilter.
class Client implements InputFilterAwareInterface
{
public function getInputFilter() {
if(!$this->_inputFilter){
$inputFactory = new InputFactory();
$inputFilter = new InputFilter();
$inputFilter->add($inputFactory->createInput(array(
'name' => 'id',
'required' => true,
'filters' => array(
array(
'name' => 'Int'
)
)
)));
$inputFilter->add($inputFactory->createInput(array(
'name' => 'name',
'required' => true,
'filters' => array(
array(
'name' => 'StripTags'
),
array(
'name' => 'StringTrim'
),
array(
'name' => 'StripNewLines'
),
array(
'name' => 'Alpha'
)
),
'validators' => array(
array(
'name' => 'StringLength',
'options' => array(
'encoding' => 'UTF-8',
'min' => 2,
'max' => 100
)
)
)
)));
$inputFilter->add($inputFactory->createInput(array(
'name' => 'surname',
'required' => true,
'filters' => array(
array(
'name' => 'StripTags'
),
array(
'name' => 'StringTrim'
)
),
'validators' => array(
array(
'name' => 'StringLength',
'options' => array(
'encoding' => 'UTF-8',
'min' => 2,
'max' => 100
)
)
)
)));
$inputFilter->add($inputFactory->createInput(array(
'name' => 'email',
'required' => false,
'filters' => array(
array(
'name' => 'StripTags'
),
array(
'name' => 'StringTrim'
)
),
'validators' => array(
array(
'name' => 'StringLength',
'options' => array(
'encoding' => 'UTF-8',
'min' => 2,
'max' => 150
)
),
array(
'name' => 'EmailAddress'
)
)
)));
$this->_inputFilter = $inputFilter;
}
return $this->_inputFilter;
}
public function exchangeArray($data){
$inputFilter = $this->getInputFilter();
$inputFilter->setData($data);
if(!$inputFilter->isValid()){
throw new \Exception('Invalid client data');
}
$cleanValues = $inputFilter->getValues();
$this->_id = (isset($cleanValues['id']) ? $cleanValues['id'] : null);
$this->_name = (isset($cleanValues['name']) ? $cleanValues['name'] : null);
$this->_surname = (isset($cleanValues['surname']) ? $cleanValues['surname'] : null);
$this->_email = (isset($cleanValues['email']) ? $cleanValues['email'] : null);
}
}
Here is my test case:
public function testExchangeArrayCallsInputFilter(){
$data = array('id' => 54,
'name' => 'john',
'surname' => 'doe',
'email' => 'john.doe#domain.com'
);
$mock = $this->getMock('Client', array('exchangeArray'));
$mock->expects($this->once())
->method('getInputFilter');
$mock->exchangeArray($data);
}
...and i'm getting the following error:
Expectation failed for method name is equal to
when invoked 1 time(s). Method was expected to be called 1 times,
actually called 0 times.
Where am i going wrong?
It all depends on what you want test and what you want mock. Basing on the name of your test I assume that you want test exchangeArray method.
The getMock method takes as second argument names of methods that you want mock. It means that they will never be called.
So, if you want to test exchangeArray method and mock getInputFilter you should pass "getInputFilter" in second argument, like below:
$mock = $this->getMock('Client', array('getInputFilter'));
$mock->expects($this->once())
->method('getInputFilter');
$mock->exchangeArray($data);
But be careful. You didn't tell your mock to return anything, so it will return null value. That means that you'll get a fatal error on the second line of exchangeArray method (trying to call a method on a non-object). You should prepare some faked filter object to deal with that, eg:
// $preparedFilterObject = ...
$mock = $this->getMock('Client', array('getInputFilter'));
$mock->expects($this->once())
->method('getInputFilter')
->will($this->returnValue($preparedFilterObject);
$mock->exchangeArray($data);
And if you want to invoke the "real" getInputFilter method - then you just can't mock this method.
I have a problem with my module views integration. I need to provide information about user who added video and timestamp. Video field is a CCK Embedded Media Field and it stores in content_field_3d_party_video table.
The schema is defined from the following code.
function MODULE_schema() {
$schema = array();
$schema['video_data'] = array(
'description' => t('Users and timestamps for video field'),
'fields' => array(
'value' => array(
'description' => t('Emfield value'),
'type' => 'varchar',
'length' => '255',
'not null' => TRUE,
'default' => '',
),
'uid' => array(
'description' => t('User id'),
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
'timestamp' => array(
'description' => t('Timestamp'),
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
),
'primary key' => array('value'),
'indexes' => array(
'timestamp' => array('timestamp'),
'uid' => array('uid'),
),
);
return $schema;
}
The hook_views_data() implementation is the following.
function MODULE_views_data() {
$data = array();
$data['video_data']['table']['group'] = t('Video Data');
$data['video_data']['table']['join'] = array(
'node' => array(
'left_table' => 'content_field_3d_party_video',
'left_field' => 'field_3d_party_video_value',
'field' => 'value',
),
'users' => array(
'left_field' => 'uid',
'field' => 'uid',
),
);
$data['video_data']['value'] = array(
'title' => t('Video value'),
'relationship' => array(
'base' => 'content_field_3d_party_video',
'base field' => 'field_3d_party_video_value',
'field' => 'value',
'handler' => 'views_handler_relationship',
'label' => t('Video value'),
),
);
$data['video_data']['uid'] = array(
'title' => t('User id'),
'relationship' => array(
'base' => 'users',
'base field' => 'uid',
'field' => 'uid',
'handler' => 'views_handler_relationship',
'label' => t('User id'),
),
);
$data['video_data']['timestamp'] = array(
'title' => t('Timestamp field'),
'field' => array(
'handler' => 'views_handler_field_date',
'click sortable' => TRUE,
),
'sort' => array(
'handler' => 'views_handler_sort_date',
),
'filter' => array(
'handler' => 'views_handler_filter_date',
),
);
return $data;
}
The table isn't included in the SQL query generated for the view.
SELECT node.nid AS nid,
node.title AS node_title,
node.language AS node_language,
node_data_field_3d_party_video.field_3d_party_video_embed AS node_data_field_3d_party_video_field_3d_party_video_embed,
node_data_field_3d_party_video.field_3d_party_video_value AS node_data_field_3d_party_video_field_3d_party_video_value,
...
node.type AS node_type,
node.vid AS node_vid
FROM node node
LEFT JOIN content_field_3d_party_video content_field_3d_party_video_video_data ON value = content_field_3d_party_video_video_data.field_3d_party_video_value
LEFT JOIN users users_video_data ON uid = users_video_data.uid
LEFT JOIN content_field_3d_party_video node_data_field_3d_party_video ON node.vid = node_data_field_3d_party_video.vid
WHERE ...
May you help me?
This is the solution the OP previously posted in the question.
To correctly join the table used for a CCK field, we must specify node_data_field_3d_party_video as left_table, instead of content_field_3d_party_video.
$data['video_data']['table']['join'] = array(
'node' => array(
'left_table' => 'node_data_field_3d_party_video',
'left_field' => 'field_3d_party_video_value',
'field' => 'value',
),
'users' => array(
'left table' => 'users',
'left_field' => 'uid',
'field' => 'uid',
),
);
I've just started looking at hooks today not 100% sure what I'm doing wrong but I'm getting an error when I try and use the $ci object in my function.
A PHP Error was encountered
Severity: Notice
Message: Trying to get property of non-object
Filename: hooks/language.php
Line Number: 12
My hooks file looks like this. It's in the hooks directory in my application folder.
class Language{
var $ci;
public function __construct(){
$this->ci =& get_instance();
}
function get_language(){
echo $this->ci->session->userdata('language');
}
}
I need to get the value in the session to use in my function. Am I not supposed to do it like this?
Thanks you!
In the Base4/5.php file the get_instance() function is written and it is conditionally loaded so it won’t be present until after it is loaded. And that's the reason its giving error.
Just done another Google search and it seems the Hook I was using Pre Controller was before the object was created I've changed the hook and it seems to work fine now.
I used post_controller_constructor for my hook, then the CI worked.
And I had to turn on hooks in the config.
Below is default application/config/hooks.php
// Stores the requested URL, which will sometimes be different than previous url
$hook['post_controller'][] = array(
'class' => 'App_hooks',
'function' => 'save_requested',
'filename' => 'App_hooks.php',
'filepath' => 'hooks',
'params' => ''
);
// Allows us to perform good redirects to previous pages.
$hook['post_controller'][] = array(
'class' => 'App_hooks',
'function' => 'prep_redirect',
'filename' => 'App_hooks.php',
'filepath' => 'hooks',
'params' => ''
);
// Maintenance Mode
$hook['post_controller_constructor'][] = array(
'class' => 'App_hooks',
'function' => 'check_site_status',
'filename' => 'App_hooks.php',
'filepath' => 'hooks',
'params' => ''
);
/* End of file hooks.php */
/* Location: ./application/config/hooks.php */
I have changed it to below and it works fine for me
// Stores the requested URL, which will sometimes be different than previous url
$hook['post_controller_constructor'][] = array(
'class' => 'App_hooks',
'function' => 'save_requested',
'filename' => 'App_hooks.php',
'filepath' => 'hooks',
'params' => ''
);
// Allows us to perform good redirects to previous pages.
$hook['post_controller'][] = array(
'class' => 'App_hooks',
'function' => 'prep_redirect',
'filename' => 'App_hooks.php',
'filepath' => 'hooks',
'params' => ''
);
// Maintenance Mode
$hook['post_controller'][] = array(
'class' => 'App_hooks',
'function' => 'check_site_status',
'filename' => 'App_hooks.php',
'filepath' => 'hooks',
'params' => ''
);
/* End of file hooks.php */
/* Location: ./application/config/hooks.php */