I am new to moodle. I'm trying to write an Events API in moodle that will be called when a user logged in and logged out. I have created a local plugin and the directory structure is as follows
os_template/
├── classes
│ └── observer.php
├── db
│ └── events.php └── version.php
db/events.php
defined('MOODLE_INTERNAL') || die();
$observers = array(
array(
'eventname' => '\core\event\user_loggedin',
'callback' => '\local_ostemplate\local_ostemplateevents::user_loggedin',
),
array(
'eventname' => '\core\event\user_loggedout',
'callback' => '\local_ostemplate\local_ostemplateevents::user_loggedin',
),
);
classes/observer.php
namespace local_ostemplate;
class local_ostemplateevents
{
public static function user_loggedin(core\event\base $event)
{
file_put_contents("test.txt","User Logged in");
}
}
But no events are called when user logged in to the moodle. Anybody please help
Your observer class "local_ostemplateevents" must have the same name as the file it is in, due to the Autoloader.
So change to something like:
os_template/
├── classes
│ └── ostemplateobserver.php
├── db
│ └── events.php
└── version.php
events.php:
defined('MOODLE_INTERNAL') || die();
$observers = array(
array(
'eventname' => '\core\event\user_loggedin',
'callback' => '\local_ostemplate\ostemplateobserver::user_loggedin',
),
array(
'eventname' => '\core\event\user_loggedout',
'callback' => '\local_ostemplate\ostemplateobserver::user_loggedin',
),
);
ostemplateobserver.php:
namespace local_ostemplate;
class ostemplateobserver {
public static function user_loggedin(core\event\base $event) {
file_put_contents("test.txt","User Logged in");
}
}
Related
I recently started programming with Zend Framework.I want to change module name, controller name and action name of a module in my framework through coding, while coding in the same framework.
Its name is Application(module & controller) and I want to change it to Institute. Is this possible through coding?
I searched through Google for help, but either i couldn't find it or understand it properly. Any help would be appreciated.
This is really just a case of renaming things:
Update all namespaces from Application to Institute in all the classes in the module including the Module.php
Update the name of the controller and it's entry in config/module.config.php
Make sure you update the name of your view directory if you have one in the module, ie view/application/index etc to view/institute/index and make sure you update the entry in module.config.php to the same path
Update name of Application directory to Institute
Update the name in the array of modules in modules.config.php or if you are using an earlier version application.config.php from under the modules key.
That's all I can think of you would need to do
******** EDIT ********
So the basic idea would be as follows:
Add a console in a new module (I've used zend mvc console but you should probably use https://github.com/zfcampus/zf-console as mvc console is deprecated)
module.config.php
<?php
namespace Rename;
use Zend\ServiceManager\Factory\InvokableFactory;
return [
'console' => array(
'router' => array(
'routes' => array(
'rename-module' => array(
'options' => array(
'route' => 'module rename <moduleNameOld> <moduleNameNew>',
'defaults' => array(
'controller' => Controller\IndexController::class,
'action' => 'rename'
)
)
)
)
)
),
'controllers' => [
'factories' => [
Controller\IndexController::class => InvokableFactory::class,
],
],
];
IndexController.php
<?php
namespace Rename\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Zend\Console\Request as ConsoleRequest;
use Zend\Mvc\Console\Controller\AbstractConsoleController;
class IndexController extends AbstractConsoleController
{
public function renameAction()
{
$request = $this->getRequest();
// Make sure that we are running in a console and the user has not tricked our
// application into running this action from a public web server.
if (!$request instanceof ConsoleRequest) {
throw new \RuntimeException('You can only use this action from a console!');
}
$moduleNameOld = $request->getParam('moduleNameOld');
$moduleNameNew = $request->getParam('moduleNameNew');
$module = file_get_contents(getcwd() . "/module/$moduleNameOld/src/Module.php", 'r+');
$updatedModule = str_replace($moduleNameOld, $moduleNameNew, $module);
file_put_contents(getcwd() . "/module/$moduleNameOld/src/Module.php", $updatedModule);
rename("module/$moduleNameOld", "module/$moduleNameNew");
}
}
This can be run like
php public/index.php module rename Application Institute
I've only done renaming the module here and renaming the namespace in the Module.php
to finish this off you would need to recursively find all .php files in the Application directory and loop over applying the string replace (which should be improved really). Then you could update the view and application level config too with similar logic and using the steps above.
The code I've written is pretty bad and probably insecure but might help you along the way
I am working on a typo3 extension and I want to generate an url from the page id. Currently I create the url by appending index.php?id=ID to $GLOBALS['TSFE']->baseURL.
Is there any other way to create a readable url from the page id, and if yes, how it can be done?
Since Extbase controllers have an UriBuilder object, you should use it:
$uri = $this->uriBuilder->reset()
->setTargetPageUid($pageUid)
->setCreateAbsoluteUri(TRUE)
->build();
You can also set an array of arguments if you need to:
$arguments = array(
array('tx_myext_myplugin' =>
array(
'article' => $articleUid,
)
)
);
Or, if you don't need an extension prefix:
$arguments = array(
'logintype' => 'login'
);
(Of course you can mix the two variants.)
And then use:
$uri = $this->uriBuilder->reset()
->setTargetPageUid($pageUid)
->setCreateAbsoluteUri(TRUE)
->setArguments($arguments)
->build();
In case you are not in extbase controller context, you can use the standard TYPO3 functionality:
$url = $GLOBALS['TSFE']->cObj->typoLink_URL(
array(
'parameter' => $pageUid,
'forceAbsoluteUrl' => true,
)
);
Some answers already exist but they do not consider some of the other methods. In particular, it is very simple to do it in Fluid. Sometimes, it also depends what you have available (e.g. if a service object is already initialized. For example, I needed to resolve the URL in a middleware and $GLOBALS['TSFE']->cObj was not available there, neither Extbase, so I used method 4).
TL;DR:
if using Fluid, use Fluid (method 1)
in PHP in Extbase Controller (FE): use $this->uriBuilder (method 2)
in PHP, non Extbase (FE): use $site->getRouter()->generateUri (method 4)
in PHP, non Extbase (BE): use BackendUtility::getPreviewUrl (method 5)
decision diagram:
.
├── Fluid
│ ├── BE
│ │ └── method1-fluid-vh-link.
│ └── FE
│ └── method1-fluid-vh-link.
└── PHP
├── BE
│ ├── in-extbase-controller
│ │ └── method2-extbase-uriBuilder
│ └── non-extbase
│ └── method5-getPreviewUrl
└── FE
├── in-extbase-controller
│ └── method2-uriBuilder
└── non-extbase
├── method3-typo3link_URL
└── method4-site-router-generateUri
If you are using Fluid, this is usually the most straightforward way to render a URL or a link, e.g. use link.page to get a link to a page or use link.action to get a link to a page with Extbase plugins - considering other query parameters as well.
<f:link.page pageUid="1">link</f:link.page>
<f:link.action pageUid="1" action="display" controller="Profile" arguments="{studyid: id}">link</f:link.action>
If you are in an Extbase Controller (FE) and $this->uriBuilder is initialized (as proposed in other answer by lorenz). Important: There are 2 classes UriBuilder, an Extbase one (\TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder) and a non Extbase one (\TYPO3\CMS\Backend\Routing\UriBuilder), use the Extbase one in FE only, see TYPO3 documentation: Extbase UriBuilder.
$this->uriBuilder->uriFor($actionName, $arguments, $controllerName, $extensionName);
// or
$uri = $this->uriBuilder->reset()
->setTargetPageUid($pageUid)
->build();
If you are not in Extbase context, but in Frontend, you can use $GLOBALS['TSFE']->cObj->typoLink_URL (as proposed in other answer by cweiske). Important: $GLOBALS['TSFE']->cObj must be initialized which may not be the case in BE or CLI context or in preview mode in FE. See documentation on TypoScript typolink for more parameters.
// slightly paranoid double-checking here, feel free to leave out if you know what you are doing
if (!$GLOBALS['TSFE'] || !$GLOBALS['TSFE'] instanceof TypoScriptFrontendController
|| !$GLOBALS['TSFE']->cObj
|| !$GLOBALS['TSFE']->cObj instanceof ContentObjectRenderer
) {
return '';
}
$params = [
'parameter' => $pageId
];
return $GLOBALS['TSFE']->cObj->typoLink_URL($params);
In FE, but not in Extbase context (same as 3, but using $site, not typoLink_URL, since TYPO3 >= v9):
$queryParameters = [
'_language' = 0,
];
$siteFinder = GeneralUtility::makeInstance(SiteFinder::class);
$site = $siteFinder->getSiteByPageId($pageId);
return (string)$site->getRouter()->generateUri(
$pageId,
$queryParameters
);
If you are in Backend context, but not in an Extbase module
BackendUtility::getPreviewUrl($pid)
See also Backend class (not Extbase UriBuilder!): TYPO3\CMS\Backend\Routing\UriBuilder to create backend links to edit records (TYPO3 Documentation: Links to Edit Records)
In case that you don't have initialized $GLOBALS['TSFE'] and would you like to avoid this bug https://forge.typo3.org/issues/71361 you have to initialize $GLOBALS['TSFE'] in this way:
if (!isset($GLOBALS['TSFE'])) {
$pid = (int)GeneralUtility::_POST('pid');
$rootline =
\TYPO3\CMS\Backend\Utility\BackendUtility::BEgetRootLine($pid);
foreach ($rootline as $page) {
if ($page['is_siteroot']) {
$id = (int)$page['uid'];
break;
}
}
$type = 0;
if (!is_object($GLOBALS['TT'])) {
$GLOBALS['TT'] = new \TYPO3\CMS\Core\TimeTracker\NullTimeTracker;
$GLOBALS['TT']->start();
}
$GLOBALS['TSFE'] =
GeneralUtility::makeInstance('TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController',
$GLOBALS['TYPO3_CONF_VARS'], $id, $type);
$GLOBALS['TSFE']->connectToDB();
$GLOBALS['TSFE']->initFEuser();
$GLOBALS['TSFE']->determineId();
$GLOBALS['TSFE']->initTemplate();
$GLOBALS['TSFE']->getConfigArray();
if
(\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('realurl')
) {
$host =
\TYPO3\CMS\Backend\Utility\BackendUtility::firstDomainRecord($rootline);
$_SERVER['HTTP_HOST'] = $host;
}
}
Generate frontend plugin / extension link from Backend Module with cHash parameter
NOTE : Dont forget to include below lines on the top your controller
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Frontend\Page\CacheHashCalculator;
$siteUrl = GeneralUtility::getIndpEnv('TYPO3_SITE_URL') . 'index.php?';
$query = array(
'id' => 57, // Target page id
'tx_event_eventfe' => array(
'controller' => 'Event',
'action' => 'show',
'eventId' => 15 // Record uid
)
);
$cacheHasObj = GeneralUtility::makeInstance(CacheHashCalculator::class);
$cacheHashArray = $cacheHasObj->getRelevantParameters(GeneralUtility::implodeArrayForUrl('', $query));
$query['cHash'] = $cacheHasObj->calculateCacheHash($cacheHashArray);
$uri = $siteUrl . http_build_query($query);
Im new to Zend 2 and are trying to migrate my Zend 1 project to Zend 2. I had an Acl plugin in my Zend 1 project that I shared with several apps using symlink. I thought now that I migrate to Zend 2 I'd create my own package in the Vendor folder. I downloaded the Skeleton project and tried to add my plugin as this:
in the vendor folder I create myname\commons\Acl and added a my Module.php
in myname\commons\Acl i created src\WebAcl\Controller\Plugin and a added WebAclPlugin.php with the namespace WebAcl\Controller\Plugin
In my myname\commons\Acl I created ./config and added module.config.php with the content
return array(
// added for Acl ###################################
' controller_plugins' => array(
'invokables' => array(
'WebAclPlugin' => 'WebAcl\Controller\Plugin\WebAclPlugin',
)
),
// end: added for Acl ###################################
);
When I run this I get:
Fatal error: Class 'WebAcl\Controller\Plugin\WebAclPlugin' not found in AbstractPluginManager.php on line 170
What am I doing wrong?
Edit: If I in my module specify the classmap it works
'Zend\Loader\ClassMapAutoloader' => array(
__DIR__ . '/autoload_classmap.php',
)
But if I use "autoload" it doesnt work
'Zend\Loader\StandardAutoloader' => array(
'namespaces' => array(
__NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__,
),
),
Edit 2: This solved the problem:
'Zend\Loader\StandardAutoloader' => array(
'namespaces' => array(
__NAMESPACE__ => __DIR__ . '/src/' *.str_replace("\\", "/", __NAMESPACE__),*
),
),
Still Im trying to figure out what composer.phar actually does? See additional question:
Additional question: I read that I should add my namespace in composer.json and run composer.phar update, which adds it to auto_namespace. I did this, but do I need to when I specify it in my module? Sorry if my questions are stupied.
The plugin manager will try to load the class using new which will make the registered autoloaders try to load the class. If there isn't an autoloader that can load this class, then you'll get the fatal error.
You don't say if myname\commons\Acl is a ZF2 module or a composer loaded package.
If it's a composer package, then you need to add:
"autoload": {
"psr-4": {
"WebAcl\\": "myname/commons/Acl/src/WebAcl"
}
}
to composer.json and then run composer.phar dumpautoload.
If you want myname/commons/Acl to be a module, then you need to add a Module.php to myname/commons/Acl that looks like this:
<?php
namespace WebAcl;
class Module
{
public function getAutoloaderConfig()
{
return array(
'Zend\Loader\StandardAutoloader' => array(
'namespaces' => array(
__NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__,
),
),
);
}
}
You now need to tell your application's ModuleManager to load this module in application.config.php:
Add 'WebAcl' to the list of 'modules'
Add the path to the module in the 'module_paths' key:
'module_paths' => array(
'WebAcl' => "./vendor/myname/commons/Acl",
'./module',
'./vendor',
),
You have to do this as there isn't a direct mapping from the namespace name (WebApi) to the path name on disk like there usually is in the ./modules directory.
The ModuleManager should now find your module and the autoloader should be able to autoload any file in the WebAcl namespace within vendor/myname/commons/Acl/src/WebApi.
Of course, the composer route is easier if you don't need any other features of a ZF2 Module.
I'm trying to use forms with modules, they should be stored inside the module. So at first my filestructure:
application/
(...other directories)
modules/
group/
controllers/
IndexController.php
(...controllers)
forms/
Create.php
views/
scripts/
(...view scripts)
Bootstrap.php
Within the IndexController, I'm trying to set the Form by
new Group_Form_Create()
and the class in Create.php is of course Group_Form_Create. I get the following error message:
Fatal error: Class 'Group_Form_Create' not found in (...)\application\modules\group\controllers\IndexController.php on line 380
The Bootstrap.php with the class Group_Bootstrap is just an empty class.
Actually, I'm using the default Zend structure, but it woun't work anyway. Any ideas wheres the problems or what could be a possible solution?
In my module bootstrap (APPLICATION_PATH/modules/group/Bootstrap.php), if use the following code:
//Loads the autoloader resources
$this->_moduleName = 'group';
$resourceLoader = new Zend_Loader_Autoloader_Resource(array(
'basePath' => APPLICATION_PATH ."/modules/".$this->_moduleName."/",
'namespace' => '',
'resourceTypes' => array(
//Tells the application where to find the forms
'form' => array(
'path' => 'forms/',
'namespace' => ucfirst($this->_moduleName).'_Form_'
),
//Tells the application where to find the models
'model' => array(
'path' => 'models/',
'namespace' => ucfirst($this->_moduleName).'_Model_'
)
)
));
I then call the forms or models like this:
$frm = new Group_Form_Create();
I use the same snippet in all my modules and I only change the value of the $this->_moduleName; each time.
Hope this helps !
It sounds like your module bootstraps are not being run. These are triggered by the module resource, which is loaded if you have:
resources.modules[] = ""
in your application.ini. So add this if it is not present.
Ideally, it should work out of box.
Add this in your bootstrap:
protected function _initAutoload() {
$autoloader = new Zend_Application_Module_Autoloader(array(
'namespace' => 'Group_',
'basePath' => dirname(__FILE__),
));
Zend_Loader_Autoloader::getInstance()->setFallbackAutoloader(true);
return $autoloader;
}
Following Pro Zend Framework techniques, I have created a module named 'Contact' in modules directory. Here's the directory structure.
|_application
|_Configs
|_application.ini
|_controllers
|_modules
|_Contact
|_Controllers
|_IndexController
|_models
|_views
Bootstrap.php
Bootstrap.php
The Bootstrap file in the application directory has an _initAutoload() function as shown below:
protected function _initAutoLoad(){
$autoLoader = Zend_Loader_Autoloader::getInstance();
$autoLoader->registerNamespace('CMS_');
$resourceLoader = new Zend_Loader_Autoloader_Resource(
array('basePath' => APPLICATION_PATH , 'namespace' => '' ,
'resourceTypes' => array('form' => array('path' => 'forms/' , 'namespace' => 'Form_') ,
'model' => array('path' => 'models/' , 'namespace' => 'Model_'))));
return $autoLoader;
}
The Bootstrap file in the modules is:
class Contact_Bootstrap extends Zend_Application_Module_Bootstrap
{
protected function _initAutoLoad(){
$autoloader=new Zend_Application_Module_Autoloader(array('namespace'=>'Contact_',
'basePath'=>dirname(__FILE__),));
return $autoLoader;
}
}
The application.ini file in the config folder has the following lines for setting up the module 'contact':
resources.frontController.moduleDirectory = APPLICATION_PATH "/modules"
resources.modules[] = ""
contact.resources.frontController.defaultControllerName = "index"
I have set up an application error controller which has a getmessage() function to display the error. When I try to load, http://localhost/zf_cms/public/contact, it gives an error:
getMessage() : Invalid controller specified (index)
The name of the index controller in modules->contact->controller is Contact_IndexController. I also created a view for index controller.
Please help me find the bug and let me know if I missed some info.
Thank you.
rename module and controller directory to lowercase . And it seems from your post that you are not adding .php extension to your IndexController do that aswell .