Drupal hooks and routes not working at all - php

I have a drupal module called hello_world.
I have an info file in drupal/web/modules/custom/hello_world called hello_world.info.yml that contains:
name: Hello World
description: Hello World module
type: module
core: 8.x
package: Custom
This works perfectly ; the module is in the extension list.
Now I tried to make a help hook so I made in the same folder a hello_world.module file with this code:
<?php
use Drupal\Core\Routing\RouteMatchInterface;
/**
* Implements hook_help().
*/
function hello_world_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'help.page.hello_world':
$output = '';
$output .= '<h3>' . t('About') . '</h3>';
$output .= '<p>' . t('This is an example module.') . '</p>';
return $output;
break;
}
}
This does not work at all. The help page is not shown.
I have also tried to make a hello world page using this controller in drupal/web/modules/custom/hello_world/src/HelloWOrldCOntroller.php:
<?php
namespace Drupal\hello_world\Controller;
use Drupal\Core\Controller\ControllerBase;
/**
* Controller for the salutation message.
*/
class HelloWorldController extends ControllerBase
{
/**
* Hello World.
*
* #return string
*/
public function helloWorld()
{
return [
'#markup' => $this->t('Hello World')
];
}
}
And this route in drupal/web/modules/custom/hello_world called hello_world.routing.yml:
hello_world.hello:
path: '/hello'
defaults:
_controller:
'\Drupal\hello_world\Controller\HelloWorldController::helloWorld'
_title: 'Our first route'
requirements:
_permission: 'access content'
This does not work either, even after clearing the cache. As I said, the hello_world.info.yml works perfectly fine, but the help hook and the controller/routing does not. The rest of the core modules work. I am using Vagrant if it matters.

Try to reinstall the module and clear caches and routes should be intended properly otherwise will run into error
hello_world.hello:
path: '/hello'
defaults:
_controller:'\Drupal\hello_world\Controller\HelloWorldController::helloWorld'
_title: 'Our first route'
requirements:
_permission: 'access content'

Related

Why I have "Not found" /admin in symfony easyAdminBundle 4 (php)

I can't open /admin page after installing easyAdminBundle in symfony app.
I do:
symfony composer req "admin:^4"
then
symfony console make:admin:dashboard
This line generate this code.
<?php
namespace App\Controller\Admin;
use EasyCorp\Bundle\EasyAdminBundle\Config\Dashboard;
use EasyCorp\Bundle\EasyAdminBundle\Config\MenuItem;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractDashboardController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class DashboardController extends AbstractDashboardController
{
#[Route('/admin', name: 'admin')]
public function index(): Response
{
return parent::index();
// Option 1. You can make your dashboard redirect to some common page of your backend
//
// $adminUrlGenerator = $this->container->get(AdminUrlGenerator::class);
// return $this->redirect($adminUrlGenerator->setController(OneOfYourCrudController::class)->generateUrl());
// Option 2. You can make your dashboard redirect to different pages depending on the user
//
// if ('jane' === $this->getUser()->getUsername()) {
// return $this->redirect('...');
// }
// Option 3. You can render some custom template to display a proper dashboard with widgets, etc.
// (tip: it's easier if your template extends from #EasyAdmin/page/content.html.twig)
//
// return $this->render('some/path/my-dashboard.html.twig');
}
public function configureDashboard(): Dashboard
{
return Dashboard::new()
->setTitle('Symfony App');
}
public function configureMenuItems(): iterable
{
yield MenuItem::linkToDashboard('Dashboard', 'fa fa-home');
// yield MenuItem::linkToCrud('The Label', 'fas fa-list', EntityClass::class);
}
}
But when I try to open /admin page I get this:
"Not Found
The requested URL was not found on this server."
This lines doesn't help:
symfony console cache:clear
symfony composer dump-autoload
rm -rf var/cache/*
I want to see the start page at easyAdminBundle like in symfony documentation. Why I can't get this?
I just solved this by changing the route for DashboardController::index from '/admin' to '/admin/d' then going to http://127.0.0.1:8000/admin/d
class DashboardController extends AbstractDashboardController
{
#[Route('/admin/d', name: 'admin')]
public function index(): Response
{
return parent::index();
}
/* ... */
}

How to limit access to a store page to the store owner?

I created a custom module to create a /store/ID/tasks page
https://www.drupal.org/project/commerce
How to limit access to this page to the store owner ?
If the current user is owner of store ID 76, he can access this page :
/store/76/tasks
But if he goes to another store, he must have denied access :
/store/89/tasks
https://git.drupalcode.org/sandbox/zenimagine-3076032
task_notify/task_notify.routing.yml
task_notify.store_page.tasks:
path: '/store/{store}/tasks'
defaults:
_controller: '\Drupal\task_notify\Controller\TaskNotifyStoreController::Tasks'
_title: 'Liste des tâches'
requirements:
_custom_access: '\Drupal\task_notify\Controller\TaskNotifyStoreController::taskAccess'
task_notify/src/Controller/TaskNotifyStoreController.php
<?php
namespace Drupal\task_notify\Controller;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Session\AccountInterface;
use Drupal\commerce_store\Entity\StoreInterface;
class TaskNotifyStoreController extends ControllerBase {
public function Tasks() {
return [
'#theme' => 'task_notify_store_template',
];
}
public function taskAccess(StoreInterface $store, AccountInterface $account = NULL, $return_as_object = FALSE) {
$result = $store->access('edit', $account, TRUE);
return $return_as_object ? $result : $result->isAllowed();
}
}
This page should be accessible only if the current user can edit the store (the site administrator and the store owner).
Access in the module code must have the same conditions as in this view :
https://i.stack.imgur.com/ZfUMo.png
I was inspired by the two files below :
https://git.drupalcode.org/project/commerce_marketplace/-/blob/8.x-1.x/src/Plugin/Action/MarketplaceIncreaseStoreLimitByOne.php
https://git.drupalcode.org/project/commerce_marketplace/-/blob/8.x-1.x/src/Plugin/Action/MarketplaceMarkAsDefault.php
In this case, we can tell Drupal that {store} is an entity and it will load the object. So we don't have to do that in the Controller function.
So your routing file can include "parameters" settings to do that.
task_notify.store_page.tasks:
path: '/store/{store}/tasks'
defaults:
_controller: '\Drupal\task_notify\Controller\TaskNotifyStoreController::Tasks'
_title: 'Liste des tâches'
requirements:
_custom_access: '\Drupal\task_notify\Controller\TaskNotifyStoreController::taskAccess'
options:
parameters:
store:
type: entity:commerce_store
Now your controller function has access to that object.
public function Tasks(StoreInterface $store) { ...
In my experience, that is NOT true of the access() method (at least when using a type-hinted parameter as we are doing here). You get a string, so you'll have to load the store manually.
public function taskAccess(string $store, AccountInterface $account) {
$store = \Drupal\commerce_store\Entity\Store::load($store);
// Check store owner against current user.
if ($store->access('edit', $account)) {
return AccessResult::allowed();
}
else {
return AccessResult::forbidden();
}
Also we need to define $account in the routing file now, as we are using type-hinted parameters (I think). So add that to the options:.
task_notify.store_page.tasks:
path: '/store/{store}/tasks'
defaults:
_controller: '\Drupal\task_notify\Controller\TaskNotifyStoreController::Tasks'
_title: 'Liste des tâches'
requirements:
_custom_access: '\Drupal\task_notify\Controller\TaskNotifyStoreController::taskAccess'
options:
parameters:
store:
type: entity:commerce_store
account: \Drupal\Core\Session\AccountProxy
$account is one of a few special parameters that we can type-hint this way. More info: https://www.drupal.org/docs/8/api/routing-system/access-checking-on-routes/advanced-route-access-checking

Using HTML.PHP instead of html.twig - not working

class DefaultController extends Controller
{
public function indexAction($page, $name) {
return $this->render('default/new.html.php'
// , array(
// $name => 'bob'
// )
);
}
}
new.html.php
<p>Welcome to the index <?= $name; ?></p>
When I use this code it is returning an error message.
But,
<p>Welcome to the index {{ name }}
this returns me correct output.
I want to use .html.php instead of .html.twig
I am going through this https://symfony.com/doc/3.4/templating/PHP.html
routing.yml
app:
path: /dd
defaults:
_controller: AppBundle:Default:index
page: 1
name: "bob"
config.yml
framework:
# ...
templating:
engines: ['twig', 'php']
Note: I am using ubuntu16.04 and Symfony 3.4
Tried locally according to Symfony documentation:
/**
* #Route("/test", name="test_route")
*/
public function test()
{
return $this->render(
'test.html.php',
[
'test_var' => 'Hello test',
]
);
}
My test.html.php:
<?php
echo $test_var;
This outputs Hello test.
PS: Tried get_defined_vars();, the variable should be seen there.

Access to user name in config file for Symfony

I'm using FMElfinder in association with TinyMCE for managing the assets (images, pdf ...) of the users (managed with FOSUSerBundle)
I've seen that this tool can handle multiple root folder, but in my case, it isn't quite usable : i would like to have a root folder for each user.
In the configuration file app/config/config.yml, there is the root path(s) defined :
fm_elfinder:
instances:
default:
locale: %locale%
...
connector:
roots:
uploads:
driver: LocalFileSystem
path: uploads/data
I was thining about "simply" changing the path to something like :
path: uploads/data/{the_username}
where the username would be the username of the currently logged user
In a controller i can do
$user = $this->get('security.token_storage')->getToken()->getUser();
$username = $user->getUsername();
But i don't know if it's possible (and if so, how) to access specifically the username of the logged user into a config file
Thank you if you have any suggestion
=================[EDIT] ==========================================
I've use the override of configuration. I think i followed the steps, but i haven't managed to make it work :
1 - Create the class
use FM\ElfinderBundle\Model\ElFinderConfigurationProviderInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
class ElfinderConfigurator implements ElFinderConfigurationProviderInterface
{
protected $container;
protected $options;
/**
* #param ContainerInterface $container
*/
public function __construct($options, ContainerInterface $container)
{
$this->container = $container;
$this->storage = $container->get('security.token_storage');
$this->options = $options;
}
/**
* #param $instance
*
* #return array
*/
public function getConfiguration($instance)
{
//retrieve basepath
$basepath_abs = $this->container->get('kernel')->getRootDir()."/../web/uploads";
$basepath = "uploads/data";
//define path for user
$userid = $this->storage->getToken()->getUser()->getId();
$root = $basepath.'/'.$userid;
$this->options['instances']['default']['connector']['roots']['uploads']['path'] = $root.'/root';
$this->options['instances']['default']['connector']['roots']['uploads']['upload_max_size'] = '2M';
$option = [
'corsSupport' => false,
'roots' => $this->options['instances']['default']['connector']['roots'],
];
$root_abs = $basepath_abs.'/data/'.$userid;
//creates dir if not available
if (!is_dir($root_abs)) {
mkdir($root_abs.'/root', 0775, true);
}
return $option;
}
}
2 - Set my service :
myvendor.mybundle.elfinder_configurator:
class: Myvendor\Mybundle\Services\ElfinderConfigurator
arguments: ["%fm_elfinder%", "#service_container"]
3 - Call the service in app/config/config.yml
fm_elfinder:
configuration_provider: myvendor.mybundle.elfinder_configurator
...
It works partially : When i open the elfinde, the directory are correctly created if they don't exists. But there must be a path problem, and i'm not sure it's well overriden because :
- The thumbs are not displayed in elfinder
- When i add the image to the editor, i don't have the correct path of the image, i have :
//app_dev.php/efconnect?cmd=file&target=l1_Q2FwdHVyZSBkJ8OpY3JhbiBkZSAyMDE2LTAxLTI0IDE0OjM2OjI0LnBuZw
instead of the actual path of the image (if i don't use the override, the tool works and gives me this path)
../../../../uploads/data/1/root/img1.png
and no image is displayed.
Also, if i look in the js console for the
efconnect?cmd=open&target=&init=1&tree=1&_=1469377765664
I see that uplMaxSize is 200M,
in any case, there is no js error in the console
I think you are looking for a custom config provider:
https://github.com/helios-ag/FMElfinderBundle/blob/master/Resources/doc/advanced-configuration.md#custom-configuration-provider
You could then inject the token storage into the service and fetch the user from
like in any controller:
services:
my_elfinder_configurator:
class: Acme\DemoBundle\elFinder\UserAwareConfigurator
arguments: ["#token_storage", "%any_container_params%"]

no route found in symfony 2 functional test

I'm trying to write a symfony 2 functional test. This is my code:
<?php
namespace WebSite\MainBundle\Tests\Controller;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
class ProductControllerTest extends WebTestCase
{
public function testPageContents()
{
$domCategoryLinksExpr = '.catalog-col-block > ul > li > a';
$client = static::createClient();
$crawler = $client->request('GET', '/catalog/');
$this->assertTrue($client->getResponse()->getStatusCode() == '200');
$countCategories = $crawler->filter($domCategoryLinksExpr)->count();
$this->assertTrue($crawler->filter($domCategoryLinksExpr)->count() > 0);
$categoryLink = $crawler->filter($domCategoryLinksExpr)->eq(rand(1, $countCategories))->link();
$crawler = $client->click($categoryLink);
}
}
But when i run this test:
phpunit -c app src/WebSite/MainBundle/Tests/Controller/
I got this:
1) WebSite\MainBundle\Tests\Controller\ProductControllerTest::testPageContents
Symfony\Component\HttpKernel\Exception\NotFoundHttpException: No route found for "GET /app_dev.php/catalog/psp"
...
/app_dev.php/catalog/psp is the dynamic value of $categoryLink->getUri(). And
this route exists and correctly works in web browser. Any ideas?
UPD:
This is my routing rules:
routing_dev.yml:
...
_main:
resource: routing.yml
....
routing.yml:
....
WebSiteCategoryBundle:
resource: "#WebSiteCategoryBundle/Controller/"
type: annotation
prefix: /
....
src/WebSite/CategoryBundle/CategoryController.php:
/**
* #Route("/catalog")
*/
class CategoryController extends Controller
{
/**
* #Route("/{alias}", name="show_category" )
* #Template()
*/
public function showAction( $alias )
{
// some action here
}
}
It works fine in browser, but seems like $crowler does`not see this annotation rules.
UPD2: The problem was in "routing_test.yml" which missing in Symfony 2 standard edition.
So I create it:
routing_test.yml:
_main:
resource: routing_dev.yml
and exception disappear. Thanks to all.
It would be nice if you posted your routing.yml
You can also take a look at:
http://symfony.com/doc/master/bundles/SensioFrameworkExtraBundle/annotations/routing.html
You can use routing annotation at your actions.
To solve your problem I would like to see your routing config.
echo $client->getResponse()->getContent() will help you with debugging (even there is an exception). It will output html of the request.
It looks like your route does not exist and might be in wrong location (wrong environment specified?)

Categories