Im wondering if someone can clear things up for me.
In my codeigniter form validation rules i have a callback called email_exists, its set as follows
->set_rules( 'login', 'Email Address', 'trim|valid_email|required|xss_clean|callback__email_exists' )
In the same controller i have the function it calls as follows
function _email_exists()
{
// Code here
}
This works perfectly, and i cant access the method from the URL because of the _ before the method name ... So its working perfect.
I have looked at the CI documentation and it says for callbacks to use a private method ... but everytime i put 'private' before the method name, it doesnt work at all.
Is it ok to just leave it as it is.
Cheers,
The method cannot be private as the validation class is not able to access the callback method.
The documentation also shows that the callback method should be declared as public.
You should leave it as it is.
It is ok to leave it as it is, because CodeIgniters _ prefix will prevent public access to the method (which means its not possible to access the function by URL as you mentioned).
The manual might be a bit confusing on this part, as they define functions prefixed by _ as private (what they really mean is hidden from public access). However a function might still be declared public (like you have in your code) but still be hidden from public access.
Related
I'm updating a PHP framework I've written. It used to just use a default behavior for routing. For example consider a case where the request goes to domain.com/package/controller/method...
$url = ["package", "controller", "method"];
//Check if package exists...
//Check if controller exists in package...
//Check if method exists in controller...
This is all well and good, and works perfectly. However, I wanted to add some additional functionality to my router. That functionality being the ability to define custom routes, and pass an anonymous function which does whatever you want.
However, supposing that the request does not match any of the user-defined routes, I want to use the default functionality I have now to check if there are additional possible routes. That way I can update old projects with the new framework and not have them break, and additionally...I just like this default behavior because most of the time routes are not that complicated and defining routes feels like a violation of DRY to me.
The problem is that I don't want to pass the user-defined routes as an array to the object constructor. Rather, I want the user to call them as methods on the base application object similar to how laravel or express handles this.
The problem is that I want the default route checking to happen AFTER the user's defined routes have been checked not before. This quasi-code might help you understand what I mean...
class App
{
__construct
{
//Check Default Routing
}
private function get()
{
//Get Request
}
private function post()
{
//Post Request
}
private function put()
{
//Put Request
}
private function delete()
{
//Delete Request
}
}
app::get();
In the above case, the default routing would take place before the user-defined routes are called. I looked at the PHP consrtuctor/destructor page and learned about __destruct. However, after reading this question I'm a little bit unsure this would work.
PHP.net says...
The destructor method will be called as soon as there are no other
references to a particular object, or in any order during the shutdown
sequence.
The first part of that explanation sounds like exactly what I want. I.E. as soon as all of the methods have been called on the application object, we'll run the __destruct function which will check if the user-defined routes were fruitful, and if not, check if the default routing system yields any results.
The problem is that I'm not sure if this is bad practice, or simply won't work. Can I require a file, set my controller, and then call a method on that controller from within __destruct? Are there limitations that would effect the code within these controllers? Supposing that there is a problem using __destruct this way, what are my alternatives, keeping in mind I don't like either of these solutions...
Having the user call the default routing as a method at the end of their script.
Passing routes in as arrays to the constructor.
I think you're confused here. Take note of this from the PHP Manual
The destructor method will be called as soon as there are no other references to a particular object, or in any order during the shutdown sequence.
To put this a different way, there's two reasons to call a destructor
The class is being garbage collected. In other words, you've overwritten or unset all the references to the class instance. This means you can't directly call this class anymore
The PHP script has reached its end and the thread is shutting down.
In other words, there's nothing left for the class to do. But in your own statement you say this
The first part of that explanation sounds like exactly what I want. I.E. as soon as all of the methods have been called on the application object, we'll run the __destruct function which will check if the user-defined routes were fruitful, and if not, check if the default routing system yields any results.
There is no "and" here to work with. That's the point. In fact, there's very few places you would use this.
What you need is to think in layers. So you'd have a controller layer that you'd call to check the methods. In turn, that controller opens a new layer that checks user functions. That class or method should return something or throw an Exception if it fails. On failure it can then try to use default methods. This is how you need to structure your program. Trying to use a destructor to do this would likely only confuse people. Make the data flow explicit, not implicit (which is what magic methods do).
Does anyone know why can't one use controller method injection in Laravel 5 to make the $router singleton available inside a controllers method, like in the code below?
use Illuminate\Routing\Router;
class WelcomeController extends Controller {
// ...
public function test($name = 'default var value', Router $router)
{
// stuff like taking the {name} part of /say-hello-to/{name?}
// ...using $router->input('name') for example
// ...assuming a route like: Route::get('say-hello-to/{name?}', 'WelcomeController#test')
}
}
An alternative way to get the same thing (idiomatic access to an url part inside a controller method) is useful, but I've already thought of a way to do this and I'm mainly interested in why this doesn't just work, as what I'm trying to get is a deeper understanding of how Laravel works and what advanced patterns can one emply when working with it.
OK, I first thought about deleting this after I figured out the answer myself in ~5min, but then again, maybe it's better to write this for others to be able to google:
When combining optional URL arguments (like 'test/{name?}') with controller method injection, always put the injected parameters before the ones with default values in the method declaration, otherwise you will end up staring at some pretty confusing errors when accessing the URL variant without the optional parameter.
So, in the example above, it should have been:
public function test(Router $router, $name = 'default var value')
...instead of:
public function test($name = 'default var value', Router $router)
And, btw, if someone more experienced with Laravel than me comes across this, please comment if you think this is a Laravel 5 bug that should be reported to the developers, or if you think this is the intended behavior for such situations.
I am trying to upgrade my CakePHP application from 1.3.6 to 2.2.4
I did all the upgrade steps based on official CakePHP upgrade documentation.
But i am struggling with this error:
Class 'Content' not found in
C:\wamp\www\cakephp-2.2.4\app\Controller\Component\OrderBaseComponent.php
on line 20
Argument 1 passed to Component::__construct() must be an instance of
ComponentCollection, none given, called in
C:\wamp\www\cakephp-2.2.4\app\Controller\Component\OrderBaseComponent.php
on line 17 and defined [CORE\Cake\Controller\Component.php, line 77]
For the first error make sure you always App::uses() every single class you use in your code.
So your Content (whatever class it is) must also be included before you can actually use it.
Only if it is a model you can just use ClassRegistry::init(), otherwise put sth like
App::uses('Content', '[TYPE]'); at the top of the file.
This second error is pretty self-explanatory!
Look into the outlined "CORE\Cake\Controller\Component.php" file and make sure your function does have the exact same arguments in your custom component:
public function __construct(ComponentCollection $collection, $settings = array()) {
//...
}
We don't have any relevant source code but generally you might add this at the top or your component file:
First:
App::uses('Content', 'Model');
And you might have to add something like in your init or construct method:
$this->Content = ClassRegistry::init('Content');
That should solve the first issue or give a clear explanation about what goes wrong. Actually this code was likely already not correctly independent functional.
I suspect it depends on the Model to be loaded already in another piece of code that's why it worked likely. A component should work not dependent on other pieces of code so adding the App::uses, App::import etc statements makes the code work always. For example when you re-use it in your other projects.
Second:
The second issue comes really with migration issues. Check that the model extends the Component class first.
Then make sure that if you implement a custom method __construct() but also init() for example that you check whether you should add a call to the parent. For example this applies to beforeFilter controller method.
public function beforeFilter() {
parent::beforeFilter();
}
Documentation and code example from: http://book.cakephp.org/2.0/en/controllers.html#the-app-controller
Relevant piece of documentation: http://book.cakephp.org/2.0/en/appendices/2-0-migration-guide.html#components
I don't know if my question should be asked here or not. Please let me know or move it/delete it if that is the case.
Question:
For the sake of learning, I'm making my own little MVC "library" for a very small personal website. Here is the process being used (please correct me if I'm not even close to doing it the right way):
All requests (except images, etc.) get sent through index.php (boostrap file).
The bootstrap file parses the request and extracts the controller and action, ex:
http://www.Domain.com/Controller/Action/Argument1/Argument2/...
Where Controller is the controller, action is the method called on the controller. In this case, it would end up being: Controller->Action ( Argument1, Argument2 );
Now, what if a user visits:
http://www.Domain.com/Controller/__destruct
or
http://www.Domain.com/Controller/__get/password
Current solution(s):
Run the request through a $config->getURIFilter () method or something
Do a check for method_exists () and is_callable (), etc.
Don't have any methods in the controller that aren't for handling a request
It just seems like this shouldn't be an issue to begin with and my design is wrong.
P.S. I've already looked at plenty of good MVC PHP frameworks (CodeIgniter, Yii, CakePHP, Zend, Swiftlet, etc.)
Either make your Controllers only handle specific actions, e.g.
/controllers
/user
loginController.php
logoutController.php
and then have classes that only do that one thing
class LoginController implements RequestHandler
{
public function handleRequest(Request $request, Response $response)
{
…
}
private function someAuxiliaryMethod() {
…
so that example.com/user/login will create a new LoginController and call the interface method handleRequest. This is a Strategy Pattern.
Or - if you dont want to split your controller actions like this - suffix your actions with a word (Zend Framework does this):
class UserController
{
public function loginAction() {
…
and in your bootstrap you add the suffix and invoke those methods then.
Yet another option would be to introduce a Router that can map URLs to Controller Actions and which can optionally do sanitizing to filter out malformed URLs, e.g. strip underscores.
I suggest that you treat any method preceded with an underscore as a private method (just show a not found page when you do your method_exists check if it starts with an underscore).
Just mark methods that you don't want to expose to your controller as private or protected.
Keep it simple!
I rolled my own MVC structure once for the same reason you're doing it, and the way I solved this was simply making an architectural decision to prefix all routable controller actions with the word "action", ie:
public function actionGetData(){
}
public function actionUpdateSomething() {
}
etc.
The reasons I did this:
You maintain full control over public/protected/private scope in your class without worrying about whether a method is inadvertently exposed via some URL.
It makes the routable actions obvious to the programmer. public function actionDoSomething() is clearly accessible via a public URL (/controllerName/doSomething), whereas public function getErDone() is not.
You're not forced to jump through hoops to identify routable actions. Simply prefix your incoming parameter with "action" and see if the method exists. Fast and simple.
I found this worked really well.
I am building a page through a series of include files. Many (not all) of the include files are classes of various things that I need stored as objects. For instance, one of my pages is:
class site {
var $siteid;
var $sitename;
function __construct($id, $name) {
$this->siteid = $id;
$this->sitename = $name;
}
function get_siteid(){
return $this->sitename;
}
and then on another page I have:
$site = new site("4","My Site");
So, on a subsequent include page I create another class called "page". While creating this class I need to reference the siteid value instantiated previously for $site, but I can't seem to get at it.
I've tried $site->get_siteid() but I get a message that says "undefined variable."
Strangely, on a regular HTML page later on, I am able to get the site id simply with $site->siteid, but from what I have read this is not a good practice, and this also doesn't work within the page class anyway.
I'm still pretty new to OO coding and so I am sure I am missing something pretty basic here, but have tried a lot of things and cannot seem to make it work.
Thanks in advance. :)
Firstly, since you're using PHP5, use access specifiers when declaring properties and methods:
Change:
var $siteid;
var $sitename;
To:
public $siteid;
public $sitename;
Or make them private or protected if preferred. See the manual for more info on visibility.
I've tried $site->get_site(id) but I
get a message that says "undefined
variable."
There is no method called get_site. There is one called get_siteid but it inexplicably returns the site name. You'll want to straighten that out.
I am able to get the site id simply
with $site->siteid, but from what I
have read this is not a good practice
There's no point in making getters/setters that simply return/set member variables. Just declare the member public and access it directly. Nothing wrong with that.
HTTP is a connectionless protocol. So state based information is not saved between requests.
The object that is instantiated (eg. $site) will not be maintained between pages.
If you have persistent data that you need to store objects you can serialize the objects and store it in a mysql table or a file. Then you can retrieve the serialized object by a using a key and the deserialize it and use it.
Several things
Intentionally or not, you have a typo. Your method is named get_siteid() but you reference $site->get_site(id)
id is not a valid variable, you should be using $id
You're method doesn't receive a parameter but you're sending one
The reason $site->siteid works is because site::$siteid is public. To prevent this, make the variable protected or private.