Je suis en train de coder mon premier module/administrateur expérimental afin de pouvoir comprendre comment Joomla effectue les appels ajax. Je n'ai besoin que d'actualiser le contenu de mon module avec des informations sur le serveur et quelques appels Google Charts. Je souhaite utiliser les techniques Joomla afin de pouvoir construire plus de modules en toute confiance à l'avenir, en utilisant les meilleures pratiques.
J'ai coupé 90% de la fonctionnalité de mon projet pour isoler les points où je suis bloqué.
mod_filefinder.php
defined('_JEXEC') or die;
require_once dirname(__FILE__) . '/helper.php';
if(!defined('DS')) define('DS', DIRECTORY_SEPARATOR);
$filefinder = new FileFinder(JFactory::getApplication()->input->post->getString('path'));
require JModuleHelper::getLayoutPath('mod_filefinder');
helper.php
class FileFinder
{
public $currentdirectory = "";
public $subdirectories = array();
public $js = "";
public $html = "";
function __construct($path = null)
{
if (!$path) {
chdir('../');
$this->currentdirectory = basename(JPATH_BASE);
$this->subdirectories = glob($this->currentdirectory.DS."*", GLOB_ONLYDIR);
$this->html = "container";
$this->js = "
jQuery(function($) {
$('#path').on('change', function() {
var path = $(this).val();
console.log({path: path});
$.ajax({
url: 'index.php?option=com_ajax&module=filefinder&method=FileFinder&format=raw', // &ignoreMessages
type: 'POST',
async: true,
cache: false,
data: {path: path},
success: function(response){
console.log(response);
}
});
});
$('#path').trigger('change');
});
";
} else {
$this->currentdirectory = $path;
$this->subdirectories = glob($this->currentdirectory.DS."*", GLOB_ONLYDIR);
}
}
public function FileFinderAjax() {
?><script>console.log('hello');</script><?php
echo "hello"; // how do I get Ajax to get in here?!?
}
}
default.php
defined('_JEXEC') or die;
if ($filefinder->html == "container") { // provide container with default contents
echo "<div id=\"filefinder_container\">";
echo "<span>", JTEXT::_("Current Directory"), " ", $filefinder->currentdirectory, "</span>";
echo "<select id=\"path\"><option value=\"\">Select a Subdirectory</option>";
foreach ($filefinder->subdirectories as $subdirectory) {
echo "<option>$subdirectory</option>"; // value=\"$filefinder->currentdirectory".DS."$subdirectory\"
}
echo "</select>";
echo "</div>";
} else { // return only the new contents to be inserted into old container
echo "<span>", JTEXT::_("Current Directory"), " ", $filefinder->currentdirectory, "</span>";
echo "<select id=\"path\"><option value=\"\">Select a Subdirectory</option>";
foreach ($filefinder->subdirectories as $subdirectory) {
echo "<option>$subdirectory</option>"; // value=\"$filefinder->currentdirectory".DS."$subdirectory\"
}
echo "</select>";
}
if ($filefinder->js) {
JHtml::_('jquery.framework');
$document = JFactory::getDocument();
$document->addScriptDeclaration($filefinder->js);
}
J'ai les fichiers index.html
Et mod_filefinder.xml
En place, je ne les ajoute tout simplement pas à mon message parce que c'est inutile.
Pour le moment, mon fichier console.log affiche ces informations après avoir sélectionné un nouveau répertoire:
{path: "administrator\cache"} POST http://localhost/jdem01/administrator/index.php?option=com_ajax&module=filefinder&method=FileFinder&format=raw 404 (Not Found)
J'ai aussi essayé:
FileFinderAjax()
une static
fonction publiqueJ'ai inutilement lu:
https://www.ostraining.com/blog/joomla/search-ajax/https://docs.joomla.org/Using_Joomla_Ajax_Interfacehttps://docs.joomla.org/J3.x:Creating_a_simple_module/Developing_a_Basic_ModuleEnvoi POST données dans le module - AJAXtilisation de AJAX dans un module personnalisé - comment le faire?
(... et d'innombrables autres ressources docs/forums/stackoverflow/stackexchange)
(... et toutes les "questions similaires" recommandées dans l'encadré jaune à droite de ma question)
J'utilise Joomla 3.8.6
Mise à jour après le support préliminaire de @jamesgarrett et @Lodder ...
Je ne reçois tout simplement pas la chaîne de réponse souhaitée.
Voici mes fichiers (dépouillés encore plus loin):
administrateur/modules/mod_filefinder/mod_filefinder.php
defined('_JEXEC') or die;
require_once dirname(__FILE__) . '/helper.php';
$filefinder = new modFileFinderHelper();
require JModuleHelper::getLayoutPath('mod_filefinder');
administrateur/modules/mod_filefinder/helper.php
class modFileFinderHelper
{
function __construct() {
$this->currentdirectory = basename(JPATH_BASE);
}
public function FileFinderAjax() {
$data = JFactory::getApplication()->input->post->getArray([]);
$path = $data['data']['path'];
?><script>console.log('<?=$path?>');</script><?php
echo "hello $path";
JExit;
}
}
administrateur/modules/mod_filefinder/tmpl/default.php
defined('_JEXEC') or die;
JHtml::_('jquery.framework');
JHtml::_('script', 'administrator/modules/mod_filefinder/ajax.js');
echo "<div id=\"filefinder_container\">{$filefinder->currentdirectory}</div>";
administrateur/modules/mod_filefinder/ajax.js
jQuery(function($) {
function loadContent(path) {
console.log({path: path});
var request = {
option : 'com_ajax',
module : 'filefinder', // to target: mod_filefinder
method : 'FileFinder', // to target: function FileFinderAjax in class modFileFinderHelper
format : 'raw',
data : {path: path}
};
console.log(request);
$.ajax({
method: 'POST',
data: request
})
.success(function(response){
console.log('response: '+response);
});
}
console.log('onload, calling ajax with default path value: '+$('#filefinder_container').html());
loadContent($('#filefinder_container').html());
$('#path').on('change', function() {
console.log('change event triggered, calling ajax with path value: '+$(this).val());
loadContent($(this).val());
});
});
Ce sont mes données console.log:
Alors laissez-moi essayer de poser cette question différemment.
Quelle est la structure de fichier la plus simple qui me permettra de:
Simple droit? S'il vous plaît aider.
Pour que la demande ajax mappe à l'aide de votre module, la classe doit être nommée "modFilefinderHelper"
De la documentation:
Les demandes de module doivent inclure la variable de module dans l'URL, associée au nom du module (c'est-à-dire module = session pour mod_session).
Cette valeur est également utilisée pour:
Nom du répertoire dans lequel rechercher le fichier d'assistance, par exemple. /modules/mod_session/helper.php Nom de la classe à appeler, par exemple. modSessionHelper
Modifier après la mise à jour de la question
J'ai mis à jour et commenté deux des fichiers où vous rencontrez des problèmes
<?php
class modFileFinderHelper
{
function __construct() {
$this->currentdirectory = basename(JPATH_BASE);
}
// static methods only (the constructor above wont run for your ajax request)
public static function FileFinderAjax() {
// Here we get the data passed via ajax - note the values themselves have not been filtered!
$data = JFactory::getApplication()->input->post->get('data',[],'array');
// Presumably you would here do something worthwhile
$response = [
'something' => 12345,
'your_path' => $data['path'],
];
// Usually you can dump json and die, but there's a inbuild responder that'll encode things and die on your behalf
// you'll see client side it also adds a few generic values like "success"
echo new JResponseJson($response);
}
}
jQuery(function($) {
// grab a dom selector so we don't have to grab it each time we update
var filefinder_container = $('#filefinder_container');
function loadContent(path) {
console.log({path: path});
var request = {
option : 'com_ajax',
module : 'filefinder', // to target: mod_filefinder
method : 'FileFinder', // to target: function FileFinderAjax in class modFileFinderHelper
format : 'raw',
data : {path: path}
};
console.log(request);
$.ajax({
method: 'POST',
data: request
})
.success(function(response){
console.log('response: '+response);
// we've got json but we need an object so let's parse it!
response = jQuery.parseJSON(response);
// and now we can use it like this.
filefinder_container.text(response.data.something + " and " + response.data.your_path);
});
}
console.log('onload, calling ajax with default path value: '+$('#filefinder_container').html());
loadContent($('#filefinder_container').html());
$('#path').on('change', function() {
console.log('change event triggered, calling ajax with path value: '+$(this).val());
loadContent($(this).val());
});
});
De plus, ce n'est pas un problème avec jQuery, mais avec certains autres frameworks FE tels que angularjs ou vuesjs, vous risquez de rencontrer un problème de Joomla qui n'était pas au courant de votre entrée car il était alimenté en tant que JSON réel, et non en tant que formulaire. Pour en finir, vous voudriez ajouter quelque chose comme
$input = Factory::getApplication()->input;
$jsonInput = json_decode(file_get_contents('php://input'));
if($jsonInput){
foreach ($jsonInput as $k => $v){
$input->def($k,$v);
}
}
Ok, la première chose à faire est d’abord, récupérez votre code JavaScript à partir du fichier PHP) et vers un fichier .js
fichier.
Le fichier doit être placé dans le répertoire media, mais juste pour une mesure temporaire, il suffit de le placer à la racine du répertoire du module.
Voici le code avec quelques modifications, telles que le passage des paramètres d'URL sous forme d'objet rwquest, par opposition à une URL directe. Cela vous aidera lorsque vous travaillez avec des sites Web multilingues et des URL SEF.
ajax.js:
jQuery(function($) {
var path = $('#path');
path.on('change', function() {
var value = $(this).val();
var request = {
option : 'com_ajax',
module : 'filefinder',
method : 'FileFinder',
format : 'raw',
'data[path]' : value,
};
$.ajax({
type: 'POST',
data: request,
success: function(response){
console.log(response);
}
});
});
path.trigger('change');
});
Le code révisé de l’assistant avec quelques modifications de code supplémentaires pour vous permettre d’obtenir les données Ajax.
helper.php:
defined('_JEXEC') or die('Restricted access');
class ModfileFinderHelper
{
public $currentdirectory = '';
public $subdirectories = array();
public $container = false;
public function __construct($path = null)
{
if (!$path)
{
chdir('../');
$this->currentdirectory = basename(JPATH_BASE);
$this->subdirectories = glob($this->currentdirectory . DS . '*', GLOB_ONLYDIR);
$this->container = true;
}
else
{
$this->currentdirectory = $path;
$this->subdirectories = glob($this->currentdirectory . DS . '*', GLOB_ONLYDIR);
}
}
public function FileFinderAjax()
{
$data = JFactory::getApplication()->input->post->getArray([]);
$path = $data['data']['server'];
var_dump($path);
exit;
// Check the browser console (Network tab) and the path should be displayed under the "response"
}
}
Et enfin le default default.php:
<?php
defined('_JEXEC') or die;
JHtml::_('jquery.framework');
JHtml::_('script', 'modules/mod_filefinder/ajax.js');
?>
<?php if ($filefinder->container) : ?>
<div id="filefinder_container">
<?php endif; ?>
<span><?php echo JText::_('Current Directory') . ' ' . $filefinder->currentdirectory; ?></span>
<select id="path">
<option value="">Select a Subdirectory</option>
<?php foreach ($filefinder->subdirectories as $subdirectory) : ?>
<option><?php echo $subdirectory; ?></option>
<?php endforeach; ?>
</select>
<?php if ($filefinder->container) : ?>
</div>
<?php endif; ?>
mod_filefinder.php:
En raison du changement de nom de classe, mettez à jour la ligne suivante dans ce fichier à partir de:
$filefinder = new FileFinder(JFactory::getApplication()->input->post->getString('path'));
à:
$path = JFactory::getApplication()->input->post->getString('path');
$filefinder = new ModfileFinderHelper($path);
Globalement, juste quelques simplifications de code et améliorations ici et là.
J'espère que cela t'aides
Sécurité
Il est recommandé d'implémenter une vérification de jeton pour les appels Ajax: