Hi I have the following drupal module
/**
* Implementation of hook_menu_alter().
*
* #param array $items
* Menu items keyed by path.
*/
function ajax_privacy_menu_alter(&$items) {
$items['node/%']['access callback'] = 'check_access';
$items['node/%']['access arguments'] = array(1);
}
function check_access($node_id)
{
if($node_id!=29)
return TRUE;
else
return FALSE;
}
If i type node/29 it returns access denied message as expected
but for other nodes ( eg: node/24 ) I get the following error
Notice: Object of class stdClass could not be converted to int in
check_access() (line 19 of
/home/pagergbr/public_html/pagerail/sites/all/modules/ajax_privacy/ajax_privacy.module).
and all the nodes in my site show up along with node/24. Please help
Your access callback gets $node object as an argument, try this:
function check_access($node) {
if ($node->nid != 29) {
...
}
}
Related
Hi guys i am trying to create a phpunit test for below function.
/**
* Get file size
*
* #param string $filePath
* #return int
*/
public function getFileSize(string $filePath): int
{
if (!file_exists($filePath)) {
return 0;
}
return filesize($filePath);
}
So far i have tried like this
/**
* Test get file size with invalid data
*/
public function testGetFileSizeWithValidData()
{
$filePath = 'rgreherher';
$service = new Tickets_Service_ContactMomentVehicle();
$result = $service->getFileSize($filePath);
$this->assertSame($result, $filePath);
}
So when i run in my terminal i am getting error as
<string:rgreherher> does not match expected type "integer".
Can anyone help me what mistake i have done.
Thanks in advance.
The error is telling you exactly what is going on, you are comparing an integer ($result) to a string ($filePath).
If I understand your test case correctly, you should replace $filePath with $filePath's size instead.
public function testGetFileSizeWithValidData()
{
$filePath = 'rgreherher';
$filePathSize = 55; // actual file size of $filePath
$service = new Tickets_Service_ContactMomentVehicle();
$result = $service->getFileSize($filePath);
$this->assertSame($result, $filePathSize);
}
In your test you assume that the file exists, but if not you must remember that php function filesize (which is in your function getFileSize) returns false and generates an E_WARNING if there is no file.
I'm using Zend Framework description and I'm trying to customize title tag like ZF2 documetation recommends, but I've got this error:
Uncaught Zend\ServiceManager\Exception\ServiceNotFoundException:
Unable to resolve service "viewHelperManager" to a factory; are you
certain you provided it during configuration? in
/var/www/html/basketmetrics/vendor/zendframework/zend-servicemanager/src/ServiceManager.php:681
Stack trace: #0
/var/www/html/basketmetrics/vendor/zendframework/zend-servicemanager/src/ServiceManager.php(757):
Zend\ServiceManager\ServiceManager->getFactory('viewHelperManag...')
1 /var/www/html/basketmetrics/vendor/zendframework/zend-servicemanager/src/ServiceManager.php(200):
Zend\ServiceManager\ServiceManager->doCreate('viewHelperManag...') #2
/var/www/html/basketmetrics/module/Stats/src/Module.php(43):
Zend\ServiceManager\ServiceManager->get('viewHelperManag...') #3
/var/www/html/basketmetrics/vendor/zendframework/zend-eventmanager/src/EventManager.php(322):
Stats\Module->setLayoutTitle(Object(Zend\Mvc\MvcEvent)) #4
/var/www/html/basketmetrics/vendor/zendframework/zend-eventmanager/src/EventManager.php(171):
Zend\EventManager\E in
/var/www/html/basketmetrics/vendor/zendframework/zend-servicemanager/src/ServiceManager.php
on line 681
This is my code on Module.php
namespace Stats;
class Module
{
const VERSION = '3.0.2';
public function getConfig()
{
return include __DIR__ . '/../config/module.config.php';
}
/**
* #param \Zend\Mvc\MvcEvent $e The MvcEvent instance
* #return void
*/
public function onBootstrap($e)
{
// Register a render event
$app = $e->getParam('application');
$app->getEventManager()->attach('render', array($this, 'setLayoutTitle'));
}
/**
* #param \Zend\Mvc\MvcEvent $e The MvcEvent instance
* #return void
*/
public function setLayoutTitle($e)
{
$matches = $e->getRouteMatch();
$action = $matches->getParam('action');
$controller = $matches->getParam('controller');
$module = __NAMESPACE__;
$siteName = 'BasketMetrics';
// Getting the view helper manager from the application service manager
$viewHelperManager = $e->getApplication()->getServiceManager()->get('viewHelperManager');
// Getting the headTitle helper from the view helper manager
$headTitleHelper = $viewHelperManager->get('headTitle');
// Setting a separator string for segments
$headTitleHelper->setSeparator(' - ');
// Setting the action, controller, module and site name as title segments
$headTitleHelper->append($action);
$headTitleHelper->append($controller);
$headTitleHelper->append($module);
$headTitleHelper->append($siteName);
}
}
I don't know If I'm doing something wrong, or if I cannot do it like in ZF2.
And meta tag "description" how can I customize it?
->get('ViewHelperManager')
Up case
My controller code:
public function postFilesAction(Request $request)
{
$validator = $this->get('validator');
$requestCredentials = RequestCredentials::fromRequest($request);
$errors = $validator->validate($requestCredentials);
...
validate method in RequestCredentials (Callback constraint).
/**
* #Assert\Callback(payload = {"errorCode" = "FILE_FILE_URL"})
*/
public function validate(ExecutionContextInterface $context)
{
if (! ($this->fileExistsAndValid() || $this->fileUrlExistsAndValid())) {
$context->buildViolation('Neither file nor file_url is present.')->addViolation();
}
}
Callback works as expected, but the value of $constraintViolation->$constraint->$payload is null.
When I'm trying to use payload in other Constraints (NotBlank, for example), it works (I can see it in ConstraintViolation object).
Is it Symfony bug or am I doing somethings wrong? Should I use some other solution to my problem? (I need to check if there's at least one of two fields (file or file_url) present in request).
In Symfony 3.0 you cannot easily access the payload in the callback when using the Callback constraint. Starting with Symfony 3.1, the payload will be passed as an additional argument to the callback (see https://github.com/symfony/symfony/issues/15092 and https://github.com/symfony/symfony/pull/16909).
I managed to solve this problem with following code in the assertion:
/**
* #Assert\Callback(payload = {"error_code" = "1"}, callback = "validate", groups = {"Default", "RequestCredentials"})
*/
public function validate(ExecutionContextInterface $context)
{
// some validation code
}
I think the problem was because of the Symfony Callback constraint constructor:
public function __construct($options = null)
{
// Invocation through annotations with an array parameter only
if (is_array($options) && 1 === count($options) && isset($options['value'])) {
$options = $options['value'];
}
if (is_array($options) && !isset($options['callback']) && !isset($options['groups'])) {
$options = array('callback' => $options);
}
parent::__construct($options);
}
When it is given $options = ['payload' => [...]] (what happened in my case) it turns it into $options = ['callback' => ['payload' => [...]]]
and then '$payload' data becomes inacessable in ConstraintViolation object.
But I'm still not sure whether it's Symfony imperfection or me not getting something and using it wrong.
Im trying to display the last accessed field when a user logs in. For this I tried using User::getLastLoginTime() . But this returns a fatal error saying
PHP Fatal error: Call to undefined method Drupal\customize_block\Plugin\Block\ContractDetails::get() in /var/www/html/core/modules/user/src/Entity/User.php on line 265
Here is my block ,in my custom module:
/**
* Provides a 'Customized contract' Block
*
* #Block(
* id = "customer_info",
* label = #Translation("Customer and contract info"),
* module = "user",
* context = {
* "current_user" = #ContextDefinition("entity:user", label = #Translation("Current User"))
* }
* )
namespace Drupal\customize_block\Plugin\Block;
use Drupal\Core\Block\BlockBase;
class ContractInfo extends BlockBase {
public function build() {
$output='';
global $base_url;
$current_user = $this->getContext('current_user');
$output.='<div>' . $current_user -> contextData . '</div>';
return array(
'#markup' => $output,
'#cache' => array(
'contexts' => array('url'),
),
);
}
}
Am I calling this method correct way?
No, you do not. You need some specific user, for example the current user or some other user object. To do it for the current user, it looks like this:
\Drupal::currentUser()->getLastAccessedTime();
I asked this question and found out that we can't get the error message thrown by a DataTransformer (according to the only user who answered, maybe it's possible, I don't know).
Anyway, now that I know that, I am stucked with a problem of validation. Suppose my model is this one: I have threads that contains several participants (users).
<?php
class Thread
{
/**
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToMany(targetEntity="My\UserBundle\Entity\User")
* #ORM\JoinTable(name="messaging_thread_user")
*/
private $participants;
// other fields, getters, setters, etc
}
For thread creation, I want the user to specify the participants usernames in a textarea, separated by "\n".
And I want that if one or more of the usernames specified don't exist, a message is displayed with the usernames that don't exist.
For example, "Users titi, tata and toto don't exist".
For that I created a DataTransformer that transforms the raw text in the textarea into an ArrayCollection containing instances of users. Since I can't get the error message provided by this DataTransformer (such a shame! Is it really impossible?), I don't check the existence of each usernames in the DataTransformer but in the Validator.
Here is the DataTransformer that converts \n-separated user list into an ArrayCollection (so that the DataBinding is ok):
<?php
public function reverseTransform($val)
{
if (empty($val)) {
return null;
}
$return = new ArrayCollection();
// Extract usernames in an array from the raw text
$val = str_replace("\r\n", "\n", trim($val));
$usernames = explode("\n", $val);
array_map('trim', $usernames);
foreach ($usernames as $username) {
$user = new User();
$user->setUsername($username);
if (!$return->contains($user)) {
$return->add($user);
}
}
return $return;
}
And here is my validator:
<?php
public function isValid($value, Constraint $constraint)
{
$repo = $this->em->getRepository('MyUserBundle:User');
$notValidUsernames = array();
foreach ($value as $user) {
$username = $user->getUsername();
if (!($user = $repo->findOneByUsername($username))) {
$notValidUsernames[] = $username;
}
}
if (count($notValidUsernames) == 0) {
return true;
}
// At least one username is not ok here
// Create the list of usernames separated by commas
$list = '';
$i = 1;
foreach ($notValidUsernames as $username) {
if ($i < count($notValidUsernames)) {
$list .= $username;
if ($i < count($notValidUsernames) - 1) {
$list .= ', ';
}
}
$i++;
}
$this->setMessage(
$this->translator->transChoice(
'form.error.participant_not_found',
count($notValidUsernames),
array(
'%usernames%' => $list,
'%last_username%' => end($notValidUsernames)
)
)
);
return false;
}
This current implementation looks ugly. I can see the error message well, but the users in the ArrayCollection returned by the DataTransformer are not synchronized with Doctrine.
I got two questions:
Is there any way that my validator could modify the value given in parameter? So that I can replace the simple User instances in the ArrayCollection returned by the DataTransformer into instances retrieved from the database?
Is there a simple and elegant way to do what I'm doing?
I guess the most simple way to do this is to be able to get the error message given by the DataTransformer. In the cookbook, they throw this exception: throw new TransformationFailedException(sprintf('An issue with number %s does not exist!', $val));, if I could put the list of non-existing usernames in the error message, it would be cool.
Thanks!
I am the one that answered your previous thread so maybe someone else will jump in here.
Your code can be simplified considerably. You are only dealing with user names. No need for use objects or array collections.
public function reverseTransform($val)
{
if (empty($val)) { return null; }
// Extract usernames in an array from the raw text
// $val = str_replace("\r\n", "\n", trim($val));
$usernames = explode("\n", $val);
array_map('trim', $usernames);
// No real need to check for dups here
return $usernames;
}
The validator:
public function isValid($userNames, Constraint $constraint)
{
$repo = $this->em->getRepository('SkepinUserBundle:User');
$notValidUsernames = array();
foreach ($userNames as $userName)
{
if (!($user = $repo->findOneByUsername($username)))
{
$notValidUsernames[$userName] = $userName; // Takes care of dups
}
}
if (count($notValidUsernames) == 0) {
return true;
}
// At least one username is not ok here
$invalidNames = implode(' ,',$notValidUsernames);
$this->setMessage(
$this->translator->transChoice(
'form.error.participant_not_found',
count($notValidUsernames),
array(
'%usernames%' => $invalidNames,
'%last_username%' => end($notValidUsernames)
)
)
);
return false;
}
=========================================================================
So at this point
We have used transformer to copy the data from the text area and generated an array of user names during form->bind().
We then used a validator to confirm that each user name actually exists in the database. If there are any that don't then we generate an error message and form->isValid() will fail.
So now we are back in the controller, we know we have a list of valid user names (possibly comma delimited or possibly just an array). Now we want to add these to our thread object.
One way would to create a thread manager service and add this functionality to it. So in the controller we might have:
$threadManager = $this->get('thread.manager');
$threadManager->addUsersToThread($thread,$users);
For the thread manager we would inject our entity manager. In the add users method we would get a reference to each of the users, verify that the thread does not already have a link to this user, call $thread->addUser() and then flush.
The fact that we have wrapped up this sort of functionality into a service class will make things easier to test as we can also make a command object and run this from the command line. it also gives us a nice spot to add additional thread related functionality. We might even consider injecting this manager into the user name validator and moving some of the isValid code to the manager.