Joomla! 2.5 Can't change task from within top level controller of my component - joomla2.5

I built a Joomla component a while ago which presents a disclaimer page immediately after logging in whereby the user has to select "I Agree" before going to the restricted site content.
The component is called com_rsdisclaimers and it has a master controller ~/coontroller.php and another (sub)controller in ~/controllers/rsdisclaimer.php defined as class RsdisclaimersControllerRsdisclaimer extends JControllerForm. The sub controller has a task/method called agree() which sets a session variable and redirects.
This all works okay in that a disclaimer is displayed and when the user clicks "agree", the sub controller task "agree" is called which sets a session variable and redirects. However I am trying to allow users to bypass this screen (component) if they have previously "agreed" to the terms. I am using JUser::getParam()/JUser::setParam() to do provide this persistance.
My design is to add logic at the component root file (~/rsdisclaimer.php) which the first checks to see if the user has the parameter already set. If so , I am trying to override and run the "agree" task straight away to handle the redirect rather than displaying the component's disclaimer page. However no matter what I do, changing the 'task' to 'agree' is simply not working on the first visit to the component after logging in on account that I and getting the master controller instead of the sub controller. How do I explicitly get a handle to the subcontroller so I can call the agree task?
Here is my top level php file:
<?php
/**
* #version 1.0.0
* #package com_rsdisclaimers
* #copyright Copyright (C) 2011 Chris Walsh. All rights reserved.
* #license GNU General Public License version 2 or later; see LICENSE.txt
*/
defined('_JEXEC') or die;
// Include dependancies
jimport('joomla.application.component.controller');
// NOTE TO SELF: If we called JRequest::getVar('task','') at this point, we
// might get a response of "rsdisclaimer.agree". However, when we
// call the same function after performing JController::getInstance('Rsdisclaimers')
// the task returned will now simply become 'agree'.
// 2014-11-20 | Chris Walsh
// Test to see if the user has previously 'agreed'...
$user = JFactory::getUser();
$accepted = $user->getParam('rsdisclaimer.accepted', '0');
echo "<pre>JCOMPONENT_BASE: accepted={$accepted}; task={$task}</pre>";
if($accepted == '1')
{
// Load the sub controller and jump straight to agree (redirects etc.)
// !! THIS IS NOT WORKING!! CAN'T GET THE SUB CONTROLLER
$task = 'agree';
$task = 'rsdisclaimer.agree';
$controller = JController::getInstance('Rsdisclaimers');
$controller->execute($task);
$controller->redirect();
}
else
{
// Execute the task
$controller = JController::getInstance('Rsdisclaimers');
$controller->execute(JRequest::getVar('task',''));
$controller->redirect();
}
The agree method in ~/controllers/rsdisclaimer.php works IF it actually gets called:
<?php
/**
* #version 1.0.0
* #package com_rsdisclaimers
* #copyright Copyright (C) 2011 Amy Stephen. All rights reserved.
* #license GNU General Public License version 2 or later; see LICENSE.txt
*/
defined('_JEXEC') or die;
jimport('joomla.application.component.controllerform');
/**
* #package Joomla.Site
* #subpackage com_rsdisclaimers
*/
class RsdisclaimersControllerRsdisclaimer extends JControllerForm
{
(snip)
/**
* Method to deal with the user selecting "agree".
*
* #return void
* #since 1.6.1
*/
function agree()
{
// Check for request forgeries.
JRequest::checkToken() or jexit(JText::_('JINVALID_TOKEN'));
// Set the session token which the plugin 'realsensedisclaimer' will check for
$session = JFactory::getSession();
$session->set('RealsenseDisclaimer', true);
// Set the agree parameter if not already set so we don't ask again
$user = JFactory::getUser();
$accepted = $user->getParam('rsdisclaimer.accepted', '0');
if($accepted == '0')
{
$user->setParam('rsdisclaimer.accepted', '1');
$user->setParam('rsdisclaimer.acceptedDate', '2014-11-20');
$accepted = $user->getParam('rsdisclaimer.accepted', '0');
}
// Redirect them to the nominated location
$app = JFactory::getApplication();
$url = 'index.php?option=com_content&view=article&id=1110&Itemid=101';
$app->redirect(JRoute::_($url, false));
}
(snip)
}
Can anyone advise how I can get a handle to the sub controller rather than the master controller?
Thanks.

Related

I am trying to alter route in my custon module. But it is already overridden in one of the contrib module

I tried to altered route it didn't work in my custom module. it is taking the altered path from contributed module. then i tried to extend the routesubscriber.php from extended module but its still didn't work.
I have cleared cache, rebuild routes, and tried to adjust weight for my custom module giving it highest weight. But still didn't work.
If anyone call help with this issue, it will be great help.
this is MyAppsRouteSubscriber.php
<?php
namespace Drupal\MyApps\Routing;
use Drupal\MyApps\Entity\ListBuilder\DeveloperAppListBuilder;
use Drupal\Core\Routing\RouteSubscriberBase;
use Symfony\Component\Routing\RouteCollection;
use Drupal\apigee_kickstart_enhancement\Routing\RouteSubscriber;
/**
* Custom MyAppsRouteSubscriber for MyApps.
*/
class MyAppsRouteSubscriber extends RouteSubscriber
{
protected function alterRoutes(RouteCollection $collection)
{
// Override the controller for the Apigee Kickstart Enhancement.
/** #var \Drupal\Core\Entity\EntityTypeInterface $app_entity_type */
foreach (\Drupal::service('apigee_kickstart.enhancer')->getAppEntityTypes() as $entity_type_id => $app_entity_type) {
if ($route = $collection->get("entity.$entity_type_id.collection_by_" . str_replace('_app', '', $entity_type_id))) {
if ($entity_type_id == 'team_app') {
$route->setDefault('_controller', TeamAppListBuilder::class . '::render');
} else {
$route->setDefault('_controller', DeveloperAppListBuilder::class . '::render');
}
}
}
}
}
and i have DeveloperAppListBuilder.php
<?php
namespace Drupal\MyApps\Entity\ListBuilder;
use Drupal\apigee_edge\Entity\DeveloperAppRouteProvider;
use Drupal\apigee_edge\Entity\ListBuilder\DeveloperAppListBuilderForDeveloper;
/**
* Renders the Apps list as a list of entity views instead of a table.
*/
class DeveloperAppListBuilder extends DeveloperAppListBuilderForDeveloper
{
/**
* {#inheritdoc}
*/
public function render()
{
//code here
}
}
First make sure your module is following the details outlined in Naming and placing your Drupal 8 module - Name your module:
It must contain only lower-case letters and underscores.
The namespace in your details indicates it is using upper camel case instead of snake cases.
Also ensure your route subscriber has a relevant my_app.services.yml services YAML file and tag it with event_subscriber or it won't be registered:
services:
my_app.route_subscriber:
class: Drupal\my_app\Routing\MyAppsRouteSubscriber
tags:
- { name: event_subscriber }
Make sure your module is enabled or it won't be working either. Debug through it to see where it still fails.

How to check "_custom_access" for whole website and not module/path?

example:
path: '/example'
defaults:
_controller: '\Drupal\example\Controller\ExampleController::content'
requirements:
_custom_access: '\Drupal\example\Controller\ExampleController::access'
This custom_access checker will be executed only when someone call mywebsite.domain/example.
But I want that this controller check all urls, run independent of path.
How can I create an independent custom access controller?
The idea for preventing routing access to a very low level (Kernel one to be precise), is to register a EventSubscriber service, subscribing to the REQUEST KernelEvent.
First of all, you will need to create a new custom module.
Once done, you will be able to create a new my_module.services.yml file which will declare a new EventSubscriber
services:
my_module.subscriber:
class: Drupal\my_module\EventSubscriber\MyCustomSubscriber
tags:
- { name: event_subscriber}
Then, create the class referenced above in my_module/src/EventSubscriber/MyCustomSubscriber.php.
Here is a tiny example which checks if the current user is logged-in before accessing any page, otherwise redirect on the login page. This following code is not complete (see the last reference for a better explanation) but it shows you the basics (subscription to the event, dependency injection, event redirection, ...)
<?php
namespace Drupal\my_module\EventSubscriber;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Url;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
class MyCustomSubscriber implements EventSubscriberInterface {
/**
* The current route match.
*
* #var \Drupal\Core\Routing\RouteMatchInterface
*/
protected $routeMatch;
/**
* Class constructor.
*
* #param \Drupal\Core\Routing\RouteMatchInterface $route_match
* The current route match.
*/
public function __construct(RouteMatchInterface $route_match) {
$this->routeMatch = $route_match;
}
/**
* {#inheritdoc}
*/
static function getSubscribedEvents() {
$events[KernelEvents::REQUEST][] = ['isLoggedIn'];
return $events;
}
/**
* It verify the page is requested by a logged in user, otherwise prevent access.
*
* #param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event
* A response for a request.
*/
public function isLoggedIn(GetResponseEvent $event) {
$route_name = $this->routeMatch->getRouteName();
// Don't run any assertion on the login page, to prevent any loop redirect.
// If intend to be used on a production project, please #see
// https://www.lucius.digital/en/blog/drupal-8-development-always-redirect-all-logged-out-visitors-to-the-login-page for a better implementation.
if ($route_name === 'user.login') {
return;
}
if (\Drupal::currentUser()->isAnonymous()) {
$dest = Url::fromRoute('user.login')->toString();
$event->setResponse(RedirectResponse::create($dest));
}
}
}
To go further, you may read those explanations of registering event subscribers & some use case:
Responding to Events in Drupal 8
How to Register an Event Subscriber in Drupal 8
Always redirect all logged out visitors to the login page
I hope it will help you.

GoAOP framework, can't get simple Aspect to work

I have been trying to play with the GoAOP library for awhile and have never successfully been able to get it to work. I have gone through the documentation several times and copied examples but haven't even been able to get them to work. All I am trying to achieve right now is a simple aspect.
I have several files as below:
app/ApplicationAspectKernel.php
<?php
require './aspect/MonitorAspect.php';
use Go\Core\AspectKernel;
use Go\Core\AspectContainer;
/**
* Application Aspect Kernel
*/
class ApplicationAspectKernel extends AspectKernel
{
/**
* Configure an AspectContainer with advisors, aspects and pointcuts
*
* #param AspectContainer $container
*
* #return void
*/
protected function configureAop(AspectContainer $container)
{
$container->registerAspect(new Aspect\MonitorAspect());
}
}
init.php
<?php
require './vendor/autoload.php';
require_once './ApplicationAspectKernel.php';
// Initialize an application aspect container
$applicationAspectKernel = ApplicationAspectKernel::getInstance();
$applicationAspectKernel->init(array(
'debug' => true, // Use 'false' for production mode
// Cache directory
'cacheDir' => __DIR__ . '/cache/', // Adjust this path if needed
// Include paths restricts the directories where aspects should be applied, or empty for all source files
'includePaths' => array(__DIR__ . '/app/')
));
require_once './app/Example.php';
$e = new Example();
$e->test1();
$e->test2('parameter');
aspect/MonitorAspect.php
<?php
namespace Aspect;
use Go\Aop\Aspect;
use Go\Aop\Intercept\FieldAccess;
use Go\Aop\Intercept\MethodInvocation;
use Go\Lang\Annotation\After;
use Go\Lang\Annotation\Before;
use Go\Lang\Annotation\Around;
use Go\Lang\Annotation\Pointcut;
/**
* Monitor aspect
*/
class MonitorAspect implements Aspect
{
/**
* Method that will be called before real method
*
* #param MethodInvocation $invocation Invocation
* #Before("execution(public Example->*(*))")
*/
public function beforeMethodExecution(MethodInvocation $invocation)
{
$obj = $invocation->getThis();
echo 'Calling Before Interceptor for method: ',
is_object($obj) ? get_class($obj) : $obj,
$invocation->getMethod()->isStatic() ? '::' : '->',
$invocation->getMethod()->getName(),
'()',
' with arguments: ',
json_encode($invocation->getArguments()),
"<br>\n";
}
}
app/Example.php
<?php
class Example {
public function test1() {
print 'test1' . PHP_EOL;
}
public function test2($param) {
print $param . PHP_EOL;
}
}
When I run php init.php it does run but just prints without the output from MonitorAspect. I don't know if I'm defining the pointcut wrong in the #Before (I've tried several variations) or if I just have a fundamental misunderstanding of how this code is suppose to work.
Any help to point me in the right direction would be greatly appreciated.
GoAOP framework was designed to work with autoloader this means that it can handle only classes that were loaded indirectly via composer autoloader.
When you manually include you class via require_once './app/Example.php'; class is loaded by PHP immediately and could not be transformed by AOP, so nothing happens, because class is already present in the PHP's memory.
In order to make AOP working you should delegate class loading to the Composer and use PSR-0/PSR-4 standard for your classes. In this case, AOP will hook autoloading process and will perform transformation when needed.
See my answer about how AOP works in plain PHP that doesn't require any PECL-extentions for additional details about internals of the framework. This information should be useful for you.

How to mock a Doctrine Repository in Zend Framework 3 using PHPUnit

I am trying to test a ZF3 controller action which, in the process, selects a user from the database via a Doctrine ORM repository using a token given as a GET-Parameter. As I need to make sure that the User exists I need to create a mock of the repository returning the user object. How do I do this?
My setup is the following:
The class UserControllerFactory is instantiating a UserController class:
class UserControllerFactory implements FactoryInterface {
/**
* #param ContainerInterface $container Zend\ServiceManager\ServiceManager
* #param string $requestedName
* #param array|NULL $options
*
* #return UserController
*/
public function __invoke(ContainerInterface $container, $requestedName, Array $options = NULL) {
$entityManager = $container->get('doctrine.entitymanager.orm_default');
$userRepository = $entityManager->getRepository('User\Entity\User');
return new UserController($container, $entityManager, $userRepository);
}}
In the UserController the acton resetPassword is called. It gets the needed parameter from the route and selects a user from the database matching the token:
public function resetPasswordAction() {
$request = $this->getRequest();
$passwordResetToken = $this->params()->fromRoute('token');
if(strlen(trim($passwordResetToken))) {
$user = $this->userRepository->findOneBy(
[
'passwordResetToken' => $passwordResetToken
]
);
...
If no user is found. The action will redirect to user to a different action.
PHPUnit test case:
public function testResetPasswordActionCanBeAccessed() {
$passwordResetToken = 'testToken1234';
$this->dispatch("/user/resetPassword/$passwordResetToken", 'GET');
$this->assertNotRedirect();
}
As there is no user having the token is will be redirected.
To my knowledge I need to create a mock of the repository (userRepository), create a mock user and use the mock repository retrieve the mock user having the token.
I am not sure if this is the right approche as I tried a lot of tutorial and never got it to work. I don't know how to "replace" the, in the action called "userRepository" with the in the unit test created mock object.
I am happy to provide more details if needed.
EDIT
As suggested by #DonCallisto (thank you) I changed my test case code to:
...
$mockedEm = $this->createMock(EntityManager::class);
$mockedUserRepository = $this->createMock('Core\Repository\EntityRepository');
$mockedEm->method('getRepository')->willReturn($mockedUserRepository);
$mockedUserRepository->method('findOneBy')->willReturn($mockedUser);
$this->dispatch("/$this->_lang/user/resetPassword/$passwordResetToken", 'GET');
...
but after calling the "dispatch" in the test case my controller call
$user = $this->userRepository->findOneBy(...)
will still return NULL instead of the mocked user object given in the test. If I debug the $mockedUserRepository, my $mockedUser is assigned correctly.
I also tried the suggested:
$mockedUserRepository->findOneBy([arrayWithParams])->willReturn($mockedUser);
But this will through an error due to the fact that $mockedUserRepository->findOneBy() is returning NULL.

Joomla 2.5 content plugin

I'm trying to deploy a simple plugin to a Joomla 2.5 installation. The code in the plugin that is outside the class declaration runs and adds the two script tags to the head. However, the code within does nothing. I can't change the $article->title or $article->text. I've copy and pasted, verbatim from different articles, but everything seems to talk only about 1.5. The 1.7 stuff that I do find only mentions changing onPrepareContent to onContentPrepare. Neither seems to do anything. I would appreciate any help!
<?php
// No direct access.
defined( '_JEXEC' ) or die( 'Restricted access' );
class plgContentPicasaGallery extends JPlugin
{
/**
*
* #param string The context of the content being passed to the plugin.
* #param mixed An object with a "text" property.
* #param array Additional parameters.
* #param int Optional page number. Unused. Defaults to zero.
* #return boolean True on success.
*/
public function onContentBeforeDisplay($context, &$article, &$params, $page = 0)
{
if (is_object($article)) {
$article->text = "omfg, wtf?";
return true;
} else {
$article = "omfg, I'm not an object, wtf?";
return true;
}
}
}
Joomla documentation & tutorials a little bit out dated, new framework changed few things.
To find proper signatures simply look at /plugins/content/... files.
Below is proper function signature & phpdoc for onContentPrepare.
/**
* #param string The context of the content being passed to the plugin.
* #param object The article object. Note $article->text is also available
* #param object The article params
* #param int The 'page' number
*/
public function onContentPrepare($context, &$article, &$params, $page = 0)
{
...
}
My noobishness with Joomla prevailed over my good sense. I was editing the plugin files on the server and I was expecting that to update the plugin. Thanks for the help!
you can use this method
jimport('joomla.form.helper');
$urla= JRequest::getVar('id');
$urlview= JRequest::getVar('view');
if ($urlview=='article')
{}
if ($urla==10<- number id article )
{}
i know framework joomla is good but its for understanding method