I'm working with MVC (php) for a tiny website.
For the moment, each view is included from the controller, but just one HTML file per controller.
To begin to optimize (I think), I want to cut some files in two/three parts :
header.php (just html headers).
Headband : this part is my problem, because if a user is connected, I want to display user informations, if he's not connected, I want to display "Register/Login" links. Am I forced to create two different files for this headband ? Is it really a good practice ? it seems not to be a proper way...
If you know some best practices or exemples, thank you.
Footer.php, not important.
I'm certainly no expert when it comes to MVC architecture, but I believe that you should have some logic in your controller to determine whether you need to display the register link or whether you need to display account info. You'd save this in a variable. Then, in your view, depending on the value of the variable you've set, you display one or the other, which can be included as other views themselves.
A bit of pseudocode:
Controller:
if (user is logged in) {
display = 'register link'
}
else {
display = 'account info'
}
View:
print display
Related
I have an original php page and a popup window written in php, I wonder how to import the variables in the original page into the popup window. One possible problem is the variable in the original page is not defined in itself but in other php pages connected to it, and it will change based on user's choice. Sincerely looking forward to suggestions, thanks!
It is like:
Two files "business.php" and "school.php" share a header file called "info.php", in "business.php" $theme = "business"; and in "school.php" $theme = "school".
In header file, I can use
if($theme=="business"){
echo "<a href='#' onclick='popitup();'>Popup</a>";
}
to have a button in the business header part.
The function for the popup window is like:
function popitup() {
var newWindow = window.open('/../popitup.php', 'name');
if (window.focus) {
newwindow.focus()
}
return false;
}
What I hope to have is using the $theme variable in "popitup.php", such as when user click the "Popup" link from business page, the popup page can show a list of options related to business information.
I would suggest something like the following:
first, start a session and maintain that for all of your pages.
The page that calls the main page sounds like the best place to centralize these things. Let's call that your controller although it may be a misnomer depending on your setup. However, if it is where the variables you are talking about are defined, it is likely close enough.
Have it call your popup, being practically persistent now. Problem solved.
You may want to look into Model-View-Controller (MVC) as well as Object Oriented Programming (OOP) concepts. Make no mistake, this is not that, but a good architecture with planning can make things much easier.
TLDR: sessions
here is a link
here is a user friendly link
edit: just incase you do not want to refactor something you have already in place, you can call your popup with a query string at the end of your url and access them with $_GET[] on the php side. Here is a link for that. Then it would be something like, page.php?option1=abcd&option2=efgh I think of that as messy and a bit antiquated, but it is valid and works fine.
another edit: another option is using cookies that you store in the user's client. It is not as fool-proof though because people may not have them on, but it may accomplish what you are looking for. Here is a link for those.
third edit: you can store your user's choices in a database and pull them with code in the popup as it is rendered.
You may remember that not long ago I asked you for some help with objects transfering through $_SESSION in PHP (more: Data loss during sending via $_SESSION from one script to another ). Currently I'm reworking the whole project and I don't have a foggiest idea how to do it properly. I mean, how to do it "according to the art", not "at any cost / the easiest (but nasty) way".
Here's the mockup of what I want to achieve (animated gif):
As you can see, I want my website to display at startup only the navigation, in which I want user to set his starting parameters. In the future, the navigation bar will have ability to be collapsed (to extend the data display section's height). When user sets the parameters (or not - for default view) and clicks "FILTER AND SORT" (which probably will be renamed to "GENERATE"), the second section should appear with data filtered and sorted as user defined.
Data is read from CSV file and stored in PHP Objects defined by my custom classes I've shown you in the question linked above. So I need to communicate data between 5 files:
FRONTEND:
index.php <-- my main file handling the website
FRONTEND-BACKEND:
navigation.php <-- file that shall be displayed in the navigation div
data.php <-- file that shall be displayed in the data section div / iframe (?)
popup.php <-- file that appears in a div over the index.php when certain DataBox is clicked; handled with tinybox2.
BACKEND:
classes.php <-- file with definitions of classes (properties and methods)
tinybox2 "library".
My communication flow is as to be:
navigation.php displayed on the top of index.php sends filtering and sorting parameters to data.php, making it appear on the bottom of index.php.
data.php and popup.php shall use classes contained in classes.php constructed from CSV file datafile.csv.
When a DataBox is clicked in data.php, popup.php appears over index.php content to display extended object data.
So, how should I do this, to make it properly? Which option will be best: $_POST, $_SESSION or maybe something else? Maybe due to embeeding all files in / over index.php it is possible to store all data in such a way, that no communication is needed? How to embeed files - with include, require or maybe other way?
There are lots of assisting questions, but still, the most important is: how to do it properly? Thank you for your help in advance :)
PS For certainty, please find below one additional usecases:
UC1: Standard use of display system
User enters website with the system
User chooses parameters for filtering and sorting
User starts generating view
Data is being read from *.csv file
During above, data is being filtered and sorted
Data is being displayed by the system to the user
Extensions:
5a. No data to display: system displays empty data section
6a. User want's to filter and sort again: back to step 2.
UC2 (OPTIONAL): User wants to share the data
UC1
User chooses an option to share data
System displays question if user wants to send it to printer, or e-mail
User chooses option (for this case: e-mail)
System asks for e-mail address
User provides e-mail address
System sends an e-mail with the current data.php data as it is displayed on website.
PPS I know I should show you some code snippets, but my current code is a mess with lots of interchanging html, php and comments, that cannot be cut of from the system (or would take me ages to clean it up to show it here). I'm asking you for help mostly, because I really want to remodel the current solution, therefore I'm rewriting the code from zero, using old one as a hint, not a template. Like Microsoft did with Windows Vista and Windows 7 :P Hope you'd understand ^^'
Okay, so here it is. The ultimate answer to a question some understands as too wide.
What was the case:
I wanted to achieve a two-section page, where the first (partent) section takes user input and uses it to filter the data in the second section. The problem was with providing parameters from the parent side to the invoked one.
What I had to change in my conception:
At first I thought about passing data with $_SESSION or other PHP way, BUT there is one major problem with such way of thinking:
As PHP is server side interpreted, it cannot dynamically add another page without refresh!
I know I didn't intent a new lightbulb or explore America, but it's still this conclusion what leaded me to accept the fact, that JavaScript usage is inevitable. I think most beginners will find this important: you need to completely change your way of thinking, as website ain't the same thing as traditional application. After this, it finally came to me (thanks to #Yoshi) that my initial problems with jQuery weren't a good reason to hold back from using it and I had to find out what they were.
Solution comes here:
Okay, so what is the solution?
I've started up with finding out what was wrong with my jQuery and... it was wrong way of interpreting "what is the scope of code included into php". If I include view/header.htm file into index.php that lays in the root directory, it will behave as it was in the root directory, not view directory. And that was the stupidest, as well as not uncommon error that one can make.
After finding this out (thank you #Yoshi again!):
I've created backend (model) for my app that can:
Read data from file
Put data into a class-based storage (that will in the future be then exported into a php file as "pseudo-database")
Then I've created a kind-of controller, that can use the model to pass data to a variable in my view.
At least I've created a view for my site, with the "parent site" (it has a backend part with a main-controller, and a frontend part with a view), and a "invoked site" that is opened through jQuery request, and contains a filtering backend and the main data view.
These 3 not-so-easy at first, but now so-so-essential, steps took me here. Please find some php-pseudocode below:
model_Data.php
<?php
// Class for single instance of data storage
model_DataSet.php
<?php
// Class for set of data instances storage
model_ReadData.php
<?php
// Code for reading CSV file with fgetcsv function
controller_DataMaster.php
<?php
require_once 'model_Data.php';
require_once 'model_DataSet.php';
require_once 'model_ReadData.php';
// Read data from file to a variable
$reader = new ReadData();
$reader->setConfiguration(//some setup);
$tmp_data = $reader->read("filename");
// Put data into the class
$dataSet = DataSet($tmp_data);
return $dataSet;
index.php (which is the main controller!)
<?php
header('Content-Type: text/html; charset="UTF-8"');
include 'view/header.htm';
header.htm contains HTML headers, includes of jQuery and jQuery-UI (for sake of datepicker) as well as css references, and (of course) physical header of the website with the input form displayed.
view.php
<?php
$import = include 'controller_DataMaster.php';
$usableData = $import->getAllDataSingles();
if (isset($_POST['data_from_the_form']))
{
// Do something!!!
}
?>
<table>
<tr>
<?php $i = 1; foreach($usableData as $singleData): ?>
<td><pre><?php print_r($singleData->getAllProperties()); ?></pre></td>
<?php if ($i++ % 3 == 0): ?>
</tr><tr>
<?php endif; ?>
<?php endforeach; ?>
</tr>
</table>
And this way you can achieve something that looks like this (currently - without any CSS applied):
So here it is. An easy, not very long, not very short answer to my own question. Case closed :)
I have code that I want to run on every page load, such as looking up menu items, looking up the users details etc. These will be displayed on partial views that make up the main view.
Where do I place this code so that it can fill my partial views with each page load? I know I can just add the code to the top of the partial view itself, but this doesn't really follow the MVC pattern.
Is there a function that is always called that I can hook into in my base controller?
You can create a base viewmodel for the repeated code and make other viewmodels inherit from it.
...such as looking up menu items, looking up the users details etc
You're a bit unclear about the type of information you want to load: in case the info is a view-component then indeed you should create a base-view and inherit from it or include it (composition) in any other view.
But, in case it is "user-information" - the data should live in a model-component that again, may live as "base-model" object that is included in other model components.
I would like to find out which strategy is the best for links, forms and DOM elements appearance manipulation (show/hide) on top level of multi modular application (admin, default, etc) ??
It should be done through ACL and it's usage I know well, permission are stored in DB.
If someone tries to access certain page (module/controller/action) that is not allowed for him, an info page is passed which says that he is not allowed. In that case all elements are visible.
I have a few strategies for elements appearance manipulation on my mind:
To set in controller
$this->view->allow_delete_link = $acl->isAllowed($role, 'delete_post'); // boolean
and to ask in view file if it is true or false and show/hide
<?php if ($this->allow_delete_link): ?>[link html] <?php endif; ?>
The drawback here is if i have 50 links on page I will need to have 50 lines of code in my controller where I am doing this and I don't like that very much.
Similar to the first except ACL is static class so view file asks if:
<?php if(My_Custom_Acl::getIsAllowed('some_resource', 'delete_post_action'){ echo 'link'; } ?>
To make one view helper which I will call upon creating every link in which I would ask if user that is logged in has access, if yes return the whole link, if not, return "" or false.
View helpers are very slow so that's my last resort.
To make separate view.phtml file for every group of users, then in controller, in which user is logged, show appropriate view.
$this->render('xx_view');
This violates DRYS, so I think this method is not good.
Is there some other strategy for something like this, because I already see that I will have headache if I choose any of these 4.
Maybe some existing plugin/class for that would be the best?
thanks in advance !
I forgot to mention, that I am using Zend framework and Zend_Acl.
3 is the best solution, because you often need to pass the database row to the isAllowed call (for example, if you need to test the owner of the post to choose if you can show the delete link).
You can't do this in the controller like you suggest in 1, because you will need one line for each row.
2 is ugly.
You can speed up resolution of view helpers by extending Zend_View: http://framework.zend.com/manual/fr/performance.view.html.
I am using a Front Controller to send the user through a series of pages with questions. Pretty much everything must be dynamic as the pages, the questions, and everything else is set in the admin interface and stored in the database.
I am tracking the user's progress through the database by storing a unique identifier in the session and storing the current page the user is on in the database so I can figure out the next page to send them to.
The thing is, there are a lot of special cases to check for. Right now the controller is over 300 lines long and the code is poorly written and I'm the one who wrote it. Plus, I am going to need to add a lot more to this system in the upcoming weeks such as user-generated content and different pages to show depending on where the user is coming from.
I can see that this controller is going to become a big mess fast if I don't organize it well.
What are some good ways or ideas to refactor this?
Generally it's easier to use URLs to determine what you should send to the client. If your questions are submitted via a <form> you can return a redirect to the next question once you have saved the answer. For example if this was one of your questions:
<form action="/questions/14" method="post">...
This would submit to /questions/14 and once you have saved the answer you can redirect to question 15:
header('Location: /questions/15');
exit;
Once you have URLs in place you can split up your front controller into parts that relate to each question. Then all you need is some routing:
if(preg_match('/\/questions\/([0-9]+)/',$_SERVER['REQUEST_URI'],$matches) > 0)
{
$question_num = (int)$matches[1];
if(!in_array($question_num, $valid_questions)) {
// return 404
}
$controller_name = 'Question_' . $question_num;
return new $controller_name;
}
else // check for urls that aren't questions ...