PHP OOP: how should I declare my component properties - php

I'm learning OOP a little and I want to get myself some good habits.
I'm writing an app which uses 'components'.
Each component is being included in component View, when $_GET['component_name'] is proper.
Components are placed in /components/component_name/ and contains files like index.php, helper.php, controller.php.
I'm doing index.php this way:
$name = "newsModule";
$helper = $name."Helper";
global $component;
$component = new $name;
$component->name = $name;
$component->template = 1;
$component->prefix = "com_";
$component->legend = array(
"time" => "create date",
"edit" => "edit",
"remove" => "delete"
);
$component->db = $component->prefix.$name;
$component->id = $_GET['id'];
$component->itemList = $helper::itemList(array(
'fields' => '*',
'db' => $component->db,
'where-field' => "title",
'where-value' => $_SESSION['keywords_'.$name]
));
Now, the $component is visible in Component View in $GLOBALS array, so I do:
$c = $GLOBALS['component'];
and using $c->db for example. And it works.
But finally - what's my point? I just think this solution is not good enough, no-oop enough etc.
I wonder if someone could share some good practices, some info and ideas about how could this code be better.
Thank you

Try these links for a good solid introduction to OOP in php.
http://code.tutsplus.com/tutorials/object-oriented-php-for-beginners--net-12762
http://www.tutorialspoint.com/php/php_object_oriented.htm
And as for good habits, find a good working example that more or less does what you want and tweak it to your needs. If you write from scratch you'll quite likely fall flat on your face at every opportunity (speaking from experience).

Related

API pagination, how to implement page token paging method?

I am working on implementing an API interface for my project.
As i know, there are different forms to make pagination through the results, like the following:
https://example.com/api/purchaseorders?page=2&pagesize=25
But, i see many APIs like google use a different approach, in which they use a "pageToken" to let the user move between the pages of results, for example:
https://example.com/api/purchaseorders?pagesize=25&pageToken=ClkKHgoRc291cmNlX2NyZWF0ZWRfYXQSCQjA67Si5sr
So instead of page=2 they used pageToken=[token].
It is not clear for me the idea of pageToken and how to implement it.
It will be helpful if you guide me to any resources so i can get more knowledge.
Thank you.
Here's a very simple standalone example using the filesystem as a keyvalue store (since a filesystem will always be available).
$requestParameters = [];
if (($token = filter_input(INPUT_GET,"pageToken")) && is_readable("/tmp/$token")) {
$requestParameters = file_get_contents("/tmp/$token");
} else {
$requestParameters = [
"q" => filter_input(INPUT_GET,"q"),
"pageSize" => filter_input(INPUT_GET,"pageSize",FILTER_VALIDATE_INT),
"page" => filter_input(INPUT_GET,"page",FILTER_VALIDATE_INT)
];
}
$nextPageRequestParameters = $requestParameters;
$nextPageRequestParameters["page"]++;
$nextPageToken = md5(serialize($nextPageRequestParameters)); //This is not ideal but at least people can't guess it easily.
file_put_contents("/tmp/$nextPageToken", serialize($nextPageRequestParameters));
//Do request using $requestParameters
$result = [ "nextPageToken" => $nextPageToken, "data" => $resultData ];
echo json_encode($result);

Codeigniter how to set API keys and Resource urls for easy access in applications

I am trying to clean up my site by putting all of my configurations in one place for easy access.
I have many different configuration dependencies for example, PayPal and Stripe public/private and sandbox/live keys as well as a number of links e.g. google recaptcha links.
I don't want to be spreading these keys around my app and then need to go hunting for them if I want to go from sandbox to live for example.
I am trying to define my API keys and most used links in the CodeIgniter config.php file like this...
$config['stripe_live'] = [
'secret' => 'secret_key_xyz',
'private' => 'private_key_xyz',
]
$config['stripe_sandbox'] = [
'secret' => 'secret_key_xyz',
'private' => 'private_key_xyz',
]
$config['paypal'] = [
'secret' => 'secret_key_xyz',
'private' => 'private_key_xyz',
]
$config['recaptcha'] = [
'site_key' => 'xyz_one_two_three',
'secret_key' => 'xyz_one_two_three',
];
$config['jquery'] = [
['jquery_link'] => base_url() . 'Public/js/jquery.js',
]
$config['bootstrap'] = [
['bootstrap_link'] => base_url() . 'Public/js/jquery.js',
]
$config['fontawesome'] = [
]
$config['google_fonts'] = [
];
$config['groupworld'] = [
'groupworld_api' => 'api_key_xyz';
];
Question one:
If I wanted to access my Stripe live private key I would have to write...
$stripe_live = $this->config->item('stripe_live');
$stripe_live['public_key'];
This is almost as much work as just copying the key to where I need it (one or two places). So is there a simpler way?
Question two:
Is is okay to put my urls in the config file like in my example above? Or would it be better to define my URLs as constants (in the constants file) and then simply access them as constants instead of writing out $this->config->item('bootstrap_link')
Thanks.
After looking at the CodeIgniter Config documentation I have come up with the following solution at least for my API configuration settings, in the example below I am using the google recaptcha API.
1 - Make a new file inside of the application/config folder and call it whatever you want... e.g. api_config.php
Inside this file put your API keys like this:
// stripe api
$config["stripe_live_public_key"] = "public_key_xyz";
$config["stripe_live_private_key"] = "public_key_xyz";
$config["stripe_sandbox_public_key"] = "public_key_xyz";
$config["stripe_sandbox_private_key"] = "public_key_xyz";
// paypal api
$config["paypal_live_public_key"] = "public_key_xyz";
$config["paypal_live_private_key"] = "public_key_xyz";
$config["paypal_sandbox_public_key"] = "public_key_xyz";
$config["paypal_sandbox_private_key"] = "public_key_xyz";
// recaptcha api
$config["recaptcha_api_url"] = 'https://www.google.com/recaptcha/api.js';
$config["recaptcha_verification_url"] = "https://www.google.com/recaptcha/api/siteverify";
$config["recaptcha_public_key"] = "lfgksl;dfg;kkkkdsjfhskjfhkjsdhfjshjksjdh";
$config["recaptcha_private_key"] = "sfkljslfjsjfahjjjjjjhjhsdfjskhajkakkajdj";
// groupworld api
// phpmailer api
2 - In the controller file load your config file and mass the data to the view like this...
$this->config->load('api_config');
$data['recaptcha_api_url'] = $this->config->item('recaptcha_api_url');
$data['recaptcha_public_key'] = $this->config->item('recaptcha_public_key');
3 - In the view file simply display your data...
<script src="<?php echo $recaptcha_api_url; ?>"></script>
<div class="g-recaptcha" data-sitekey="<?php echo $recaptcha_public_key; ?>"></div>
Now to change your config data in multiple places simply go to the api_config.php file and paste in your new keys.
As I'm a newbie can't comment :/ .
I will start with question 2. Its ok to keep like this. But stripe,paypal are payment gateways it will be good to store it in db as Yogesh said and retrieve to use it.It will also comes in handy if you want to provide user to edit it.
For js,css links you can put them in a view like 'includefiles.php' and load it in all pages as we load views.
for easy retrieval of your data, you can use helper functions.
<?php
//paymentdetail_helper
function getpaymentdetailhelper(someid or gateway name as arg eg.$id){
$ins=& get_instance();
$ins->load->database();
//your queries $ins->db->query();
return $data;
}
?>
Save this in application/helpers as paymentdetail_helper.php and load it as usual. more info about helpers in questionInfo about helper
Its my idea. :) You're welcome with suggestions

Should I use an array or object to reference system settings?

I am building a site that has 30-40 system settings. These are editable in a text file. I want to make sure that I set the site up with the most logical and less resource-intensive method of pulling these settings.
I have been thinking about using an array:
$system['language'] = 'en';
$system['version'] = '0.1';
And referencing them throughout the site like: echo $system['version'];
Or, I can set them up as an object:
class SiteConfig {
public $language = 'en';
public $version = '0.1';
}
$system = new SiteConfig;
And referencing them throughout the site like: echo $system->version;
Which is best to use, or does anyone have a better suggestion?
The approach taken by some frameworks (Laravel for example) is to create a settings file, that you pull in with require.
Your various settings are all defined in that file in a single array, that is returned:
settings.php
<?php
return array(
'language' => 'en',
'version' => '0.1',
'timezone' => 'America/Sao_Paulo',
);
Then you can use it like:
$system = require 'settings.php';
echo $system['version'];
See example #5 on the php.net docs for include for more about this return.

Routing, Navigation and State in MVC

I am attempting to refactor my app using the MVC paradigm.
My site displays charts. The URLs are of the form
app.com/category1/chart1
app.com/category1/chart2
app.com/category2/chart1
app.com/category2/chart2
I am using Apache Rewrite to route all requests to index.php, and so am doing my URL parsing in PHP.
I am working on the enduring task of adding an active class to my navigation links when a certain page is selected. Specifically, I have both category-level navigation, and chart-level sub-navigation. My question is, what is the best way to do this while staying in the spirit of MVC?
Before my refactoring, since the nav was getting relatively complicated, I decided to put it into an array:
$nav = array(
'25th_monitoring' => array(
'title' => '25th Monitoring',
'charts' => array(
'month_over_month' => array(
'default' => 'month_over_month?who=total&deal=loan&prev='.date('MY', strtotime('-1 month')).'&cur='.date('MY'),
'title' => 'Month over Month'),
'cdu_tracker' => array(
'default' => 'cdu_tracker',
'title' => 'CDU Tracker')
)
),
'internet_connectivity' => array(
'title' => 'Internet Connectivity',
'default' => 'calc_end_to_end',
'charts' => array(
'calc_end_to_end' => array(
'default' => 'calc_end_to_end',
'title' => 'calc End to End'),
'quickcontent_requests' => array(
'default' => 'quickcontent_requests',
'title' => 'Quickcontent Requests')
)
)
);
Again, I need to know both the current category and current chart being accessed. My main nav was
<nav>
<ul>
<?php foreach ($nav as $category => $category_details): ?>
<li class='<?php echo ($current_category == $category) ? null : 'active'; ?>'>
<?php echo $category_details['title']; ?>
</li>
<?php endforeach; ?>
</ul>
</nav>
and the sub-nav was something similar, checking for current_chart instead of current_category.
Before, during parsing, I was exploding $_SERVER['REQUEST_URI'] by /, and breaking the pieces up into $current_category and $current_chart. I was doing this in index.php. Now, I feel this is not in the spirit of the font controller. From references like Symfony 2's docs, it seems like each route should have its own controller. But then, I find myself having to define the current category & chart multiple times, either within the template files themselves (which doesn't seem to be in the spirit of MVC), or in an arbitrary function in the model (which would then have to be called by multiple controllers, which is seemingly redundant).
What is the best practice here?
Update: Here's what my front controller looks like:
// index.php
<?php
// Load libraries
require_once 'model.php';
require_once 'controllers.php';
// Route the request
$uri = str_replace('?'.$_SERVER['QUERY_STRING'], '', $_SERVER['REQUEST_URI']);
if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && (!empty($_GET)) && $_GET['action'] == 'get_data') {
$function = $_GET['chart'] . "_data";
$dataJSON = call_user_func($function);
header('Content-type: application/json');
echo $dataJSON;
} elseif ( $uri == '/' ) {
index_action();
} elseif ( $uri == '/25th_monitoring/month_over_month' ) {
month_over_month_action();
} elseif ( $uri == '/25th_monitoring/cdu_tracker' ) {
cdu_tracker_action();
} elseif ( $uri == '/internet_connectivity/intexcalc_end_to_end' ) {
intexcalc_end_to_end_action();
} elseif ( $uri == '/internet_connectivity/quickcontent_requests' ) {
quickcontent_requests_action();
} else {
header('Status: 404 Not Found');
echo '<html><body><h1>Page Not Found</h1></body></html>';
}
?>
It seems like when month_over_month_action() is called, for instance, since the controller knows the current_chart is month_over_month, it should just pass that along. This is where I'm getting tripped up.
There are not "best practices" in this area. Though, there are some, that are more often used then others, and some, that are extremely bad ideas (unfortunately, these two groups tend to overlap).
Routing in MVC
While technically not a part of MVC design pattern, when applied to Web, your application needs to know which controller to initialize and what method(s) to call on it.
Doing explode() to gather this sort of information is a bad idea. It is both hard to debug and maintain. A much better solution is to use regular expressions.
Basically you end up having a list of routes, that contain a regular expression and some fallback values. You loop through that list and on fists match extract the data and apply default values, where data was missing.
This approach also frees you to have much wider possibilities for order of parameters.
To make the solution easier to use, you can also add functionality, that turns a notation string into a regular expression.
For example (taken from some unit-test, that I have):
notation:     test[/:id]
expression: #^/test(:?/(?P<id>[^/\.,;?\n]+))?$#
notation:     [[/:minor]/:major]
expression: #^(:?(:?/(?P<minor>[^/\.,;?\n]+))?/(?P<major>[^/\.,;?\n]+))?$#
notation:     user/:id/:nickname
expression: #^/user/(?P<id>[^/\.,;?\n]+)/(?P<nickname>[^/\.,;?\n]+)$#
While creating such a generator will not be all that easy, it would be quite reusable. IMHO the time invested in making it would be well spent. Also, the use of (?P<key>expression) construct in regular expressions provides you with a very useful array of key-value pairs from the matched route.
Menus and MVC
The decision about which menu item to highlight as active should always be the responsibility of current view instance.
More complicated issue is where the information, that is necessary for making such decision, comes from. There are two source if data that are available to a view instance: information that was passed to view by controller and data, that view requested from model layer.
The controller in MVC takes the user's input and, based on this input, it changes the state of current view and model layer, by passing said values. Controller should not be extracting information from model layer.
IMHO, the better approach in this case is to relay on model layer for information about both menu content and the currently active element in it. While it's possible to both hardcode the currently active element in view and relay on controllers passed informations, MVC is usually used in large scale application, where such practices would end up hurting you.
The view in MVC design pattern is not a dumb template. It's a structure, that is responsible for UI logic. In context of Web that would mean creating a response from multiple template, when necessary, or sometimes just simply sending an HTTP location header.
Well, I had almost the same trouble when was writing CMS-like product.
So I've spend some time trying to figure out how to make this work and keep the code more maintainable and clean as well.
Both CakePHP and Symfony route-mecanisms have a bit inspired me but it wasn't good enough for me.
So I'll try to give you an example of how I do this now.
My question is, what is the best way to do this while staying in the
spirit of MVC?
First, In general, best practice is NOT TO USE procedural approach with MVC in web development at all.
Second, keep the SRP.
From references like Symfony 2's docs, it seems like each route should
have its own controller.
Yeah, that's right approach, but it doesn't mean that another route match can't have the same controller, but different action.
The main disadvantage of your approach (code that you have posted) is that you mix responsibilities and you're not implementing MVC-inspired pattern.
Anyway, MVC in PHP with procedural approach is just a horrible thing.
So, what exactly you are mixing is:
Route mechanism logic (It should be another class) not in a "controller" and route map as well
Request and Response responsibilites (I see that it isn't obvious to you)
Class autoloading
Controller logic
All those "parts" should have one class. Basically, they have to be included in index or bootstrap files.
Also, by doing so:
require_once 'controllers.php';
You automatically include ALL controllers per match (even on no-match). It actually has nothing to do with MVC and leads to memory leaks.
Instead, you should ONLY include and instantiate the controller that matches against URI string.
Also, be careful with include() and require() as they may lead to code duplication if you include the same file somewhere twice.
And also,
} elseif ( $uri == '/' ) {
index_action();
} elseif ( $uri == '/25th_monitoring/month_over_month' ) {
month_over_month_action();
} elseif ( $uri == '/25th_monitoring/cdu_tracker' ) {
cdu_tracker_action();
} elseif ( $uri == '/internet_connectivity/intexcalc_end_to_end' ) {
intexcalc_end_to_end_action();
It's extremely unwise to do a match using if/else/elseif control structures.
Okay, what if you have 50 matches? or even 100? Then you need to write 50 or 100 times to write else/elseif accordingly.
Instead, you should have a map and (an array for example) iterate over it on each HTTP request.
The general approach of using MVC with routing mechanism comes down to:
Matching the request against route map (and keep somewhere parameters if we have them)
Then instantiate appropriate controller
Then pass parameters if we have them
In PHP, the implementation would look like:
File: index.php
<?php
//.....
// -> Load classes here via SPL autoloader or smth like this
// .......
// Then -> define or (better include route map from config dir)
$routes = array(
// -> This should default one
'/' => array('controller' => 'Path_To_home_Controller', 'action' => 'indexAction'),
'/user/:id' => array('controller' => 'Path_to_user_controller', 'action' => 'ViewAction'),
// -> Define the same controller
'/user/:id/edit' => array('controller' => 'Path_to_user_controller', 'action' => 'editAction'),
// -> This match we are going to hanlde in example below:
'/article/:id/:user' => array('controller' => 'SomeArticleController', 'action' => )
);
// -> Also, note you can differently handle this: array('controller' => 'SomeArticleController', 'action' => )
// -> Generally controller key should point to the path of a matched controller, and action should be a method of the controller instance
// -> But if you're still on your own, you can define it the way you want.
// -> Then instantiate common classes
$request = new Request();
$response = new Response();
$router = new Router();
$router->setMap( $routes );
// -> getURI() should return $_SERVER['REQUEST_URI']
$router->setURI( $request->getURI() );
if ( $router->match() !== FALSE ) {
// -> So, let's assume that URI was: '/article/1/foo'
$info = $router->getAll();
print_r ( $info );
/**
* Array( 'parameters' => Array(':id' => '1', ':user' => 'foo'))
* 'controller' => 'Path_To_Controller.php'
* 'action' => 'indexAction'
*/
// -> The next things we are going to do are:
// -> 1. Instantiate the controller
// -> 2. Pass those parameters we got to the indexAction method
$controller = $info['controller'];
// -> Assume that the name of the controller is User_Controller
require ( $controller );
// -> The name of class should also be dynamic, not like this, thats just an example
$controller = new User_Controller();
$arguments = array_values( $info['parameters'] );
call_user_func_array( array($controller, $info['action']), $arguments );
// -> i.e we just called $controller->indexAction('1', 'foo') "dynamically" according to the matched URI string
// -> idealy this should be done like: $response->send( $content ), however
} else {
// -> In order not to show any error
// -> redirect back to "default" controller
$request->redirect('/');
}
In my MVC-inspired applications I do route like this:
(Where I use Dependecy Injection and keep the SRP)
<?php
require (__DIR__ . '/core/System/Auload/Autoloader.php');
Autoloader::boot(); // one method includes all required classes
$map = require(__DIR__ . '/core/System/Route/map.php');
$request = new Request();
$response = new Response();
$mvc = new MVC();
$mvc->setMap( array_values($map) );
// -> array_values($map) isn't accurate here, it'd be a map of controllers
// -> take this as a quick example
$router = new Router();
$router->setMap( $map );
$router->setURI( $request()->getURI() );
if ( $router->match() !== FALSE ) {
// -> Internally, it would automatically find both model and view instances
// -> then do instantiate and invoke appropriate action
$router->run( $mvc );
} else {
// No matches handle here
$request->redirect('/');
}
I found this to be more appropriate for me, after poking around Cake and Symfony.
One thing I want to note:
It's not that easy to find good articles about MVC in PHP. Most of them are just wrong.
(I know how it feels, because first time I've started to learn from them, like so many people do)
So my point here is:
Don't make the same mistake like I did before. If you want to learn MVC, start doing this by reading
Zend Framework or Symfony Tutorials. Even the ones are bit different, the idea behing the scene is the same.
Back to the another part of the question
Again, I need to know both the current category and current chart
being accessed. My main nav was
<nav>
<ul>
<?php foreach($nav as $category => $category_details): ?>
<li class='<?php echo ($current_category == $category) ? null : 'active'; ?>'>
<?php echo $category_details['title']; ?>
</li>
<?php endforeach; ?>
</ul>
</nav>
First of all, don't concatenate the string, instead use printf() like:
<?php echo $category_details['title']; ?>
If you need this to be everywhere (or at least in many different templates), I'd suggest to this to have in a common abstact View class.
For example,
abstract class View
{
// -> bunch of view reusable methods here...
// -> Including this one
final protected function getCategories()
{
return array(
//....
);
}
}
class Customers_View extends View
{
public function render()
{
$categories =& $this->getCategories();
// -> include HTML template and then interate over $categories
}
}

What are the step you have to go through when updating an application to be multilingual?

I need to update an application which is built on Zend Framework.
Most of the text is hard-coded in views scripts, forms, etc.
The application will be available in say, 3 languages AND is language specific (the content is not the same for all) and will have one domain per language (ie: mygreatsite.com, monsupersite.com, ilmiosupersite.com, etc.)
First question:
What is the best way to "handle" this kind of application?
I can imagine several solution like:
One copy per language, using different db, etc... (probably not the best way for maintenance)
Only one application, handling different content, db, etc, depending on the locale (based on the route)
Second question:
What should I need to know about the existing code to start the "migration"?
What about any best practice when building a i18n website?
What are the best adapter? (I already used gettext() and I think it's the best)
I am by no means an expert but this is what I do.
I use array as my translation adapter because it’s easier for my clients to update as they are just regular Joes. And I use translation keys instead of sentences. For example
Some people would use
$this->translate(‘Some sentence to translate’);
I use
$this->translate(‘default-index-dashboard-title’);
This makes it far easier for me to know where the text I’m looking for is to change. I don’t know if there are any advantages other than that though.
You will need to setup your translation adapter and translation cache (if you want) in your bootstrap. I do mine like this:
protected function _initLocale()
{
$locale = new Zend_Locale(Zend_Locale::BROWSER);
$config = Zend_Registry::get('config');
Zend_Registry::set('Zend_Locale', $locale->toString());
return $locale;
}
protected function _initTranslation()
{
try{
$translate = new Zend_Translate(array('adapter' => 'array', 'content' => ROOT . '/callmanagement/languages/' . strtolower(Zend_Registry::get('Zend_Locale')) . '.php'));
}catch(Exception $e){
$translate = new Zend_Translate(array('adapter' => 'array', 'content' => ROOT . '/callmanagement/languages/en_gb.php'));
}
Zend_Registry::set('Zend_Translate', $translate);
return $translate;
}
I would use a single code base unless the sites are completely different and store the shared data in one database and have other databases for the site specific stuff.
You can setup multiple db adapters either in the bootstrap or in the congfig.
$dbLocal = new Zend_Db_Adapter_Pdo_Mysql(array(
'host' => 'localhost',
'username' => $result['user'],
'password' => $result['password'],
'dbname' => $result['database']
));
Zend_Db_Table_Abstract::setDefaultAdapter($dbLocal);
$dbShared = new Zend_Db_Adapter_Pdo_Mysql(array(
'host' => 'localhost',
'username' => ‘root’,
'password' => 'pass',
'dbname' => 'dbname'
));
Zend_Registry::set('db_local', $dbLocal);
Zend_Registry::set('db_shared', $dbShared);
return $dbLocal;
You can get Zend Form to translate for you just put your translation key into the label field.
$this->addElement(‘text’, ‘test’, array(‘label’ => ‘translation-key’, ‘required’ => true)); etc.
Then if you are using Zend_Db_Table_Abstract classes you can change the default schema and database connection like this:
class Default_Model_Table_Topics extends Zend_Db_Table_Abstract
{
protected $_name = 'topics';
protected $_id = 'topic_id';
protected $_rowClass = 'Default_Model_Topic';
protected $_schema = 'dbname';
protected $_adapter = 'db_shared';
}
If you need any more examples I’ll try and help.

Categories