I have a custom component, in fact several. Each will have raw and hard-coded html at the beginning and end of their /view/default.php
I have a system plugin that needs to get this html and in some cases change it to something else, that can be managed in the back end. As a content plugin this works fine on all com_content articles, but it is ignored by components, my understanding is system plugins can do this but i can't get the data into the plugin and return it
example of component text ($text1, $text2 are defined at the top of the document)
JPluginHelper::importPlugin( 'system' );
JPluginHelper::importPlugin('plgSystemMyplugin');
$dispatcher =& JDispatcher::getInstance();
$data = array($text1, $text2); // any number of arguments you want
$data = $dispatcher->trigger('onBeforeRender', $data);
<article>
<div class="spacer" style="height:25px;"></div>
<div class="page_title_text">
<h1>title</h1>
<?php var_dump($data); ?>
</div>
<section>
my plugin:
jimport( 'joomla.plugin.plugin' );
class plgSystemMyplugin extends JPlugin {
function onBeforeRender() {
if (JFactory::getDocument()->getType() != 'html') {
return;
}
else {
$document=JFactory::getDocument();
$document->addCustomTag('<!-- System Plugin has been included (for testing) -->');
$document=JResponse::getBody();
$bob=JResponse::getBody();
$db = &JFactory::getDbo();
$db->setQuery('SELECT 1, 2 FROM #__table');
$results = $db->loadRowList();
$numrows=count($results);
if($numrows >0) {
foreach($results as $regexes) {
$document = str_replace($regexes[0],$regexes[1],$document);
}
return $document;
}
else {
$document = 'error with plugin';
}
JResponse::setBody($document);
return $document;
}
}
}
at the moment $data returns an array with a key 1 and value (string) of "" (blank/empty).
but not the data from the database I am expecting.
in simple terms I have {sometext} in my file and my database and it should return <p>my other text</p>
can you help?
thanks
Ok. Well looking at this deeper there is a couple of issues that jump out. The biggest being that you save getBody into a variable named $bob but then switch everywhere to using $document which is the object form above, not the content.
Also, you had a return $document hanging out in the middle of the code that prevented you from seeing that you were going to set $document as the new body. Probably should be more like below:
$bob=JResponse::getBody();
$db = &JFactory::getDbo();
$db->setQuery('SELECT 1, 2 FROM #__table');
$results = $db->loadRowList();
$numrows=count($results);
if($numrows >0) {
foreach($results as $regexes) {
$bob = str_replace($regexes[0],$regexes[1],$bob);
}
}
else {
$bob = 'error with plugin';
}
JResponse::setBody($bob);
return $document;
}
Original Thoughts:
Two thoughts to get you started. I'm not sure that this will actually fully answer the question, but should get you moving in the right direction.
First, you should not have to trigger the system plugin. They are system plugins, so the system will take care of that for you. If you wanted to use content plugins in your component (which you can definitely do!) then you would have to trigger them like your first set of code. In this case, don't bother with the entire dispatch section.
Second, your plugin looks set up to grab the body from the JDocument correctly, so that should work.
The likely issue is that the entire system plugin is just not being triggered. Make sure that it is installed and everything is named correctly. It has to be at plugins/system/myplugin/myplugin.php based on this name and make sure that the xml file with this also references myplugin as the plugin name. If not, the system won't find the class but likely won't throw an error. It will just skip it. This gives me trouble every time.
To do some checking just to make sure it gets called, I usually throw an echo or var_dump near the top of the file and just inside the function. Confirm that the function is at least getting called first and you should be most of the way to getting this to work.
Related
Finally completed the frontend of my website, I am now looking at coding the backend which needs an overhaul, the coding is very messy and uses far too many SQL Connections and commands, so much so that the host is complaining about it.
One of the main problems I am having is the Site Settings page, problem is this page will soon contain over 10 different options, and I prefer not to have a MySQL Update simply updating the option field to what it already is, so I am wondering if anyone has any ideas?
This is the structure of my options table, nice and simple which I recently changed from an awful layout.
What would be the best way to edit these options without having to update every single one, and what would be the best way to have them in a function? Currently, the function I have was made back when I was new to coding, and you can see that is is very uneffective(note it uses the old table structure)
function site_upd($site_title, $site_email, $maint_status, $maint_mess, $upload_disable, $site_url, $reg_status, $land_mess)
{
if( !$site_title )
{
echo $this->errorMessage('There was no <b>site title</b> supplied, therefore we can not continue with this request.', 'error');
}
else
{
$this->logQuery('Updated site settings');
$query = "UPDATE `table`.`settings` SET `site_title` = '".$site_title."', `site_email` = '".$site_email."', `maint_status` = '".$maint_status."', `maint_mess` = '".$maint_mess."', `upload_disable` = '".$upload_disable."', `site_url` = '".$site_url."', `registration_status` = '".$reg_status."', `landing_mess` = '".$land_mess."' WHERE `settings`.`sid` = '1'";
mysql_query($query) or die(''.mysql_error()); } }
So yeah, there is the awful old structure and my old way of doing things, before I get stuck into coding I want other peoples opinions on what is the best way to do this!
You can work with $_POST Variable to simplify the update method.
This is what I usually do:
First I create a non specific function to update:
function update_db($table, $id,$idvalue,$field,$fieldvalue){
return mysql_query("update ".$table." set ".$field."=".$fieldvalue." where ".$id."=".$idvalue);
}
Then i create the specific function to the table (config i.e):
function update_table_config($name,$value){
return update_db("config","name",$id,"value",$value);
}
In the form i call all <input> like its name on the table:
Site Name: <input type="text" name="site_name">
...
and in the "action" page i check $_POST array:
$data_array=$_POST;
if(check_variables($data_array)){
foreach ($data_array as $key=>$value){
update_table_config($key,$value);
}
}
the function check_variables has all the checks that you need for all the fields:
function check_variables($data){
if($data["site_title"]=="") return false;
if(!is_numeric($data["landing_mess"])) return false;
...
return true;
}
with this methods if in the future you have to include more fields in the configuration table you only have to add the <input> field and a check in check_variables function if needed
I am trying to implement a SAX based parser but somehow it only recognizes the start of the element and the end, the content is not provided in the logs. The variable holding the XML is filled correctly, I checked through a simple log.
Here is the code:
<?php
function startElementHandler($parser, $name, $attribs) {
if($name == "id"){
$id = TRUE;
}
}
function endElementHandler($parser,$name){
$id = FALSE;
}
function characterDataHandler($parser,$data){
if($id == TRUE){
echo $data;
}
}
global $id;
$id = FALSE;
$parser = xml_parser_create();
xml_set_element_handler($parser, "startElementHandler","endElementHandler");
xml_set_character_data_handler($parser,"characterDataHandler");
$xml = file_get_contents("http://itunes.apple.com/de/rss/topfreeapplications/limit=100/xml");
xml_parse($parser,$xml);
//xml_parser_free($parser);
?>
Any suggestion how I could recieve the content? Maybe I am missing something strange I am not aware of at the moment.
best regards
tim
Per your comment, $id never becomes true. Maybe you want attribs to have an id and not the name of the element. For example, if you have the XML
<div id="x"> blah </div>
You get
$name="div", $attribs={"id":"x"}
(this came out a bit of php-python, but i hope you get my point)
Is that really your bug?
According to http://www.phpcatalyst.com/php-compare-strings.php you should always compare strings using ===. Is that your bug?
You only used the xml_set_element_handler-callbacks. Those only:
Set up start and end element handlers
If you also want to retrieve the content of those tags, you'll also need to register the xml_set_character_data_handler-callback. Because this one:
Set up character data handler
I'm trying to teach myself php... so please be kind and bear with me.
I'm trying to follow this tutorial on how to cache files... the page I want to cache is HTML only, so I've modified the php to just deal with data. I know the caching part is working, it's when I try to modify the results that I get a "Catchable fatal error: Object of class Caching could not be converted to string" in the str_replace line below.
I've tried using the __toString method here, and I've tried using serialize. Is there something I'm missing?
Edit: Oh and I've even tried casting operators.
$caching = new Caching( "my.htm", "http://www.page-I-want.com/" );
$info = new TestClass($caching);
$info = str_replace( "<img src='/images/up.jpg'>","<div class='up'></div>", $info );
My var_dump($caching); is as follows:
object(Caching)#1 (2) { ["filePath"]=> string(9) "cache.htm" ["apiURI"]=> string(27) "http://www.page-I-want.com/" }
Ok, I see now that the problem is with the caching.php not returning the value to the $caching string. Can anyone check out the link below and help me figure out why it's not working? Thanks!
I just posted my entire caching.php file here.
The code in on the site you link works by downloading the page from URL you give and parse it for artists and then save them to the cache file. The cache-object only contains two variables; filePath and apiURI. If you want to modify how the page is parse and converted to the cached XML-file, you should change the stripAndSaveFile function.
Here is an example of how to modify the Caching.php to do what you wanted:
function stripAndSaveFile($html) {
//mange the html code in any way you want
$modified_html = str_replace( "<img src='/images/up.jpg'>","<div class='up'></div>", $html );
//save the xml in the cache
file_put_contents($this->filePath, $modified_html);
}
Edit:
Other option is to extend the Caching class, in your php-code using the class you could do:
class SpecialCaching extends Caching {
var $html = "";
function stripAndSaveFile($html) {
//mange the html code in any way you want
$this->html = $html;
}
}
$caching = new SpecialCaching( "my.htm", "http://www.page-I-want.com/" );
$info = $caching->html;
$info = str_replace( "<img src='/images/up.jpg'>","<div class='up'></div>", $info );
I have a class designated for a certain site. In that site I have different functions to retrieve data from the database and store that data into an array. I have other functions within the same class that take the data and format it into html and returns the html containing the data from the database.
For example...
function GetUserProfile($userID){
$query = 'SELECT * FROM users WHERE userID='.$userID;
.......
blah blah blah
.......
$user = mysqli->fetch_assoc();
return $user;
}
function FormatUserProfile($user, $showDesc = false){
$profile = '< h1 >'.$user['userName'].'< / h1 >';
if($showDesc){
$profile .= '< div >'.$user['description'].'< / div >';
}
return $profile;
}
...
So if i had a function to solely gather information, and another function to solely format that gathered information.
Mainly because I will be showing the same data on different pages, but Different pages show different data, like a search would only bring up the users name, where as the users profile page would bring up the username and the description for example.
Is that good practice, or is there a better way to do this?
It's a good practice. Personally, I use the following template "engine":
<?php
class Template{
static function show($path, $arg = NULL){
include "templates/$path.php";
}
static function get($path, $arg = NULL){
ob_start();
self::show($path, $info);
$block = ob_get_contents();
ob_end_clean();
return $block;
}
}
In your case the template would be like this:
<?php
echo '<h1>'.$arg['user']['userName'].'</h1>';
if($arg['showDesc']){
echo '<div>'.$arg['user']['description'].'</div>';
}
?>
You could unpack the array with the template arguments, but I prefer to keep it all in one place, so the code is less confusing. (You always know what is coming from the input, and what's defined in the template this way. To keep things shorter, you might use $_ instead of $arg too.) For a small example like this, the benefit is not obvious, but for larger templates it save a lot of variable manipulation, as you can use PHP's own templating abilities.
You can use Smarty template engine or something
similar.
It's templates are stored separately and look like this: http://www.smarty.net/sampleapp/sampleapp_p5.php
this is my front controller
$pages = array("matches", "boards", "search", "articles", "interviews", "userlist", "teams", "servers", "awards", "gallery", "qids");
if (!$_SERVER['QUERY_STRING']) include('home_en.php');
elseif (isset($_GET['matchid'])) include('matchid.php');
elseif (isset($_GET['boardid'])) include('boardid.php');
elseif (isset($_GET['articleid'])) include('articleid.php');
elseif (isset($_GET['interviewid'])) include('interviewid.php');
elseif (isset($_GET['userid'])) include('profi.php');
elseif (isset($_GET['teamid'])) include('teamid.php');
elseif (isset($_GET['serverid'])) include('serverid.php');
elseif (isset($_GET['awardid'])) include('awardid.php');
elseif (isset($_GET['galleryid'])) include('galleryid.php');
elseif (isset($_GET['threadid'])) include('threadid.php');
elseif (isset($_GET['blogid'])) include('blogid.php');
..
elseif (in_array($_GET['content'], $pages)) include($_GET['content']);
else echo "File not found =(";
could i somehow add the identifiers to the array too? but i want the pages as index.php?matchid=9438 and for regular pages: index.php?content=matches
would really aprricate some ideas
thanks!
My Suggestion, From My Comment is this:
In order to check what type of id it is, you should use two $_GET parameters. One is the type (match, award, server, etc), one is the ID. That way you don't have to check for 500 different $_GET parameters, just the value of 2. Much more standardized.
Second, you want to make all of it under 1 file for the ID showing.
In the spirit of writing less code, not more, it would be relatively easy to change the SQL statement to grab the record based on if $_GET['type'] was match, award, team, etc. This is of course given that they will probably look the same. If they don't, instead of writing new code to grab each type, instead write code to display it differently
All Variables in this code much be validated/sanatized beforehand.
// First Get the Type
$type = $_GET['type'];
// Then the ID
$id = $_GET['id'];
// SANITIZE YOUR DATA. Replace this with your sanitization.
die("SANITIZE YOUR DATA HERE");
// Get Data Here
$sql = "SELECT * FROM table WHERE type=".$type." AND id=".$id;
$data = mysql_query($sql);
// Next, Include a template based on the data.
// Global the variable so it can be used in the file
Global $data;
include($type."-template.php");
I agree with Tom -- you should look into using a framework such as Zend, Cake, Symfony, Kohana, CodeIgniter, ez-Components, or Seagull. The advantage of using a framework is that they have already solved a lot of issues for you, including:
1) How to structure your code
2) How to interpret pretty urls (i.e. /x/1/y/2 instead of ?x=1&y=2)
3) Where to put certain types of code (html, php, configs, etc)
4) How to fix something you can't figure out (because these frameworks have communities)
and much much more...
That being said, maybe you don't want all the overhead of using a framework (it does require you to learn a lot). In that case, I recommend Rasmus Lerdorf's "No Framework PHP Framework". Rasmus is the creator of PHP, so you know he knows his stuff.
Lastly, to answer your actual question, here's how I would do it:
could i somehow add the identifiers to the array too?
i want the pages as index.php?matchid=9438
and for regular pages: index.php?content=matches
Sure, but yes, as Chacha102 said, you will need 2 parameters: $area (page) and $id.
Example: index.php?area=articles&id=2345
Then you can re-organize & simplify your 'front controller' this way:
/index.php
/areas/articles.php
/areas/boards.php
etc.
Instead of naming the templates articleid.php, just call it articles.php -- this way your area name also tells you which template to use.
$valid_areas = array("matches", "boards", "search", "articles",
"interviews", "userlist", "teams", "servers",
"awards", "gallery", "qids");
$area = strtolower(trim($_REQUEST['area'])); //if you are not posting any forms, use $_GET instead
$id = (int)$_REQUEST['id']; //if you are not posting any forms, use $_GET instead
if(!$id)
{
include('home_en.php');
}
if(!in_array($area), $valid_areas))
{
echo 'Sorry, the area you have requested does not exist: '.$area;
exit();
}
else
{
$template = '/templates/'.$area.'.php';
if(!file_exists($template))
{
echo 'Sorry, the file you have requested does not exist: '.$area.' '.$id);
}
else
{
include($template);
}
}
It might help to go ahead and use a framework such as Zend:
http://framework.zend.com/
You could do this:
<?php
$controllerDefault = 'home';
function sanitize($str)
{
return str_replace(array('.', '/', '\\'), '', $str);
}
//Prevent of Remote File Inclusion
$controller = sanitize($_GET['controller']);
$id = intval($_GET['id']);
if (empty($controller))
{
$controller = $controllerDefault;
}
if (!empty($id))
{
$controller .= 'id';
}
$controllerFile = $controller . '.php';
if (!file_exists($controllerFile)
|| $controller == 'index') //for not recursive index.php include :)
{
exit('Controller "'.$controllerFile.'" not exists');
}
include($controllerFile);
?>
Using this code you can use your application like:
http://yoursite.com/index.php //include('home.php')
http://yoursite.com/index.php?id=285230 //include('homeid.php')
http://yoursite.com/index.php?controller=matches //include('matches.php')
http://yoursite.com/index.php?controller=matches&id=28410 //include('matchesid.php')
http://yoursite.com/index.php?controller=notexists //ERROR! Controller "notexists" not exists
http://yoursite.com/index.php?controller=../../etc/passwd //ERROR! Controller "etcpasswd" not exists
I hope you like it
PD: the code is not tested, but I hope you catch my idea