Breaking apart url and passing parts in MVC - php

I am trying to create an MVC application and am currently working on the Bootstrap file. I get the URL and explode it then assign the parts to the Controller Method and Method arguments. But, I can't find a way to pass multiples arguments to the method.
mysite/newuser/login/user_name/user_pass
newuser -> Controler of the site
login -> currently used method
user_name -> first argument
user_pass -> second_argument
For example
$url = "mysite/newuser/login/user_name/user_pass";
$path = expload('/',$url);
$this->controler = $path[0];
$this->method = $path[1];
For the arguments I create a second array like this:
// Set the substring path as method properties
if (isset($path[2])) {
$this->url_sub_path = $path[2];
$sub_path = explode('/', $this->url_sub_path);
if (isset($sub_path)) {
$this->model_properties = $sub_path;
When i assign the controllers a set
$site_controler = $this->controler;
include CONTROLER.$site_controler . '.php';
$new_instans = new $site_controler();
But the problem is here:
$site_method = $this->model;
$new_instans->{$site_method}($this->model_properties);
$this->model_properties is Array
if the function is:
public function login($user_name,$user_pass){
// some code
}
I need to pass the url properties they are Array and I have two variables in my function
The idea is to convert the array to variables
Or you could pass an idea in how to pass arguments from URL to my model

Try this function: http://www.php.net/manual/en/function.call-user-func-array.php
call_user_func_array ($new_instans->{$site_method} , $this->model_properties )

If, as you say, $this->model_properties is an array, you can do one of two things.
Case 1: Maintain the function declaration, and access the array's elements before calling the function.
The login() function (maintain it's declaration):
public function login($user_name,$user_pass){
// some code
}
To call the function, do this:
$array = $this->model_properties;
$param1 = $array[0]; //The numeric index may vary, depending on how this array was populated
$param2 = $array[1];
$new_instans->{$site_method}($param1, $param2);
Case 2: Change the function declaration to receive an array, and access the array's elements inside the function.
The login() function, change the declaration:
public function login($arrayParams){
//Access the parameters like this
$param1 = $arrayParams[0]; //The numeric index may vary, depending on how this array was populated
$param2 = $arrayParams[1];
//The rest of your code...
}
To call the function simply pass the array, as you're already doing:
$new_instans->{$site_method}($this->model_properties);
Independently of which version you choose to solve your problem, the important part is this:
$param1 = $array[0];
$param2 = $array[1];
Here, you assign the content of the array's elements of index 0 and 1 to a variable, allowing you to treat those values independently.

Related

Using a function in php - what am I doing wrong?

$users = [
"Andrew",
"Max",
"Larry",
"Ricardo",
"Lucy",
"Marcus",
"Sophie"
];
$sector_rel = [];
$location_rel = [];
function sectorRel($user){
return sector_rel[] = round(1/rand(1,10),3);
}
function locationRel($user){
return $location_rel[] = round(1/rand(1,20),3);
}
foreach($users as $user){
sectorRel($user);
locationRel($user);
}
This:
function sectorRel($user){
return sector_rel[] = round(1/rand(1,10),3);
}
Should be/could be:
function sectorRel($user){
global sector_rel;
sector_rel[] = round(1/rand(1,10),3);
}
The problem is that the functions don't have access to the array variables. You can import them into the function scope using the keyword global, if they are indeed global variables. Now, having global variables isn't a good thing, and for a small test it's okay, but eventually you'll be eliminating your globals and this solution won't work.
But alternatively, you could pass the array variables to the function as an argument. However, this still introduces a lot of logic in the function. The function has to be told about the array, it must know that it needs to add a value to the end, and it also needs to calculate the actual value to add.
So better, make the function just return the calculated value and add it to the array outside of the function:
function sectorRel($user){
// Assuming your are going to use 'user' here somewhere?
return round(1/rand(1,10),3);
}
function locationRel($user){
return round(1/rand(1,20),3);
}
foreach($users as $user){
sector_rel[] = sectorRel($user);
$location_rel[] = locationRel($user);
}
You can then wrap this entire snippet of code into another function and call that to populate the arrays. That way, you've quite reasonably split the responsibilities of the functions and have a piece of code that looks nice and clean.
You do not need to use return in either of sectorRel or locationRel. At the moment this will return the reference to that array and it is not being stored in a variable. You would need to store them in a variable or just get rid of the return. My PHP is a little weak at the moment but you should probably append the values in those functions to the array.
Also if you have a parameter called $user for each of those functions you should either use that parameter or just get rid of it.

Using a non-static object method with usort

I am trying to sort an array of values using a class method. The values are as follows
$agegroups = array("08","910","1112","1314","1516","1718","1999");
However, they can be any combination of numbers. The values above correspond to age groups used on my site and are are defined in a database table, so I can't hard code them. I have an object that contains an array of age group defintions like this
private $agegroups = array();
function __construct() {
// retrieve data from the database
while($data = $sth->fetch()) {
$ag = new StdClass();
$ag->low = $data['low']; //stores the low end of the age group
$ag->high = $data['high'] //stores the high end of the age group
$this->agegroups[$data['key']] = $ag;
}
}
$data['key'] corresponds to the $agegroups array defined above. In the same class, I defined a sort method
function sort($a,$b) {
$aAG = $this->agegroups[$a];
$bAG = $this->agegroups[$b];
return $aAG->low > $bAG->low ? 1 : -1;
}
My understanding is that usort can only use a static method. However my object needs to retrieve the values from a database, so I can't make it static.
I tried using an anonymous function with usort that could use an instance of the class defined outside the function but I get an error about an undefined object.
$agObj = new agegroups();
$agegroups = usort($agegroups, function($a, $b){
global $agObj;
return $agObj->sort($a,$b);
});
The error I get is Fatal error: Call to a member function sort() on a non-object
I release I can create a new instance of the object inside the anonymous function but I don't want to have to query the database each time. Is there a way to use my class to sort these values?
Wherever a function is required, you can use array(object, functionName) to call the method on that object.
usort($agegroups, array($agObj, 'sort'));
BTW, you shouldn't assign the result of usort back to agegroups. The sorting functions modify the array in place; they return a boolean, not the reordered array.

How can I make an array of type "class" in PHP?

I have the following class with several properties and a method in PHP (This is simplified code).
class Member{
public $Name;
public $Family;
public function Fetch_Name(){
for($i=0;$i<10;$i++){
$this[$i]->$Name = I find the name using RegExp and return the value to be stored here;
$this[$i]->Family = I find the family using RegExp and return the value to be stored here;
}
}//function
}//class
In the function Fetch_Name(), I want to find all the names and families that is in a text file using RegExp and store them as properties of object in the form of an array. But I don't know how should I define an array of the Member. Is it logical or I should define StdClass or 2-dimension array instead of class?
I found slightly similar discussion here, but a 2 dimensional array is used instead of storing data in the object using class properties.
I think my problem is in defining the following lines of code.
$Member = new Member();
$Member->Fetch_name();
The member that I have defined is not an array. If I do define it array, still it does not work. I did this
$Member[]= new Member();
But it gives error
Fatal error: Call to a member function Fetch_name() on a non-object in
if I give $Member[0]= new Member() then I don't know how to make $Member1 or Member[2] or so forth in the Fetch_Name function. I hope my question is not complex and illogical.
Many thanks in advance
A Member object represents one member. You're trying to overload it to represent or handle many members, which doesn't really make sense. In the end you'll want to end up with an array that holds many Member instances, not the other way around:
$members = array();
for (...) {
$members[] = new Member($name, $family);
}
Most likely you don't really need your Member class to do anything really; the extraction logic should reside outside of the Member class, perhaps in an Extractor class or something similar. From the outside, your code should likely look like this:
$parser = new TextFileParser('my_file.txt');
$members = $parser->extractMembers();
I think you should have two classes :
The first one, Fetcher (or call it as you like), with your function.
The second one, Member, with the properties Name and Family.
It is not the job of a Member to fetch in your text, that's why I would make another class.
In your function, do your job, and in the loop, do this :
for($i = 0; $i < 10; ++$i){
$member = new Member();
$member->setName($name);
$member->setFamily($family);
// The following is an example, do what you want with the generated Member
$this->members[$i] = $member;
}
The problem here is that you are not using the object of type Member as array correctly. The correct format of your code would be:
class Member{
public $Name;
public $Family;
public function Fetch_Name(){
for($i=0;$i<10;$i++){
$this->Name[$i] = 'I find the name using RegExp and return the value to be stored here';
$this->Family[$i] = 'I find the family using RegExp and return the value to be stored here';
}
}
}
First, $this->Name not $this->$Name because Name is already declared as a member variable and $this->Name[$i] is the correct syntax because $this reference to the current object, it cannot be converted to array, as itself. The array must be contained in the member variable.
L.E: I might add that You are not writing your code according to PHP naming standards. This does not affect your functionality, but it is good practice to write your code in the standard way. After all, there is a purpose of having a standard.
Here you have a guide on how to do that.
And I would write your code like this:
class Member{
public $name;
public $family;
public function fetchName(){
for($i=0;$i<10;$i++){
$this->name[$i] = 'I find the name using RegExp and return the value to be stored here';
$this->family[$i] = 'I find the family using RegExp and return the value to be stored here';
}
}
}
L.E2: Seeing what you comented above, I will modify my answer like this:
So you are saying that you have an object of which values must be stored into an array, after the call. Well, after is the key word here:
Initialize your object var:
$member = new Memeber();
$memebr->fechNames();
Initialize and array in foreach
$Member = new Member();
foreach ($Member->Name as $member_name){
$array['names'][] = $member_name;
}
foreach ($Member->Family as $member_family) {
$array['family'][] = $member_family;
}
var_dump($array);
Is this more of what you wanted?
Hope it helps!
Keep on coding!
Ares.

How to write a controller that sends an array as a URL parameter?

In some MVC platforms, a controller method accepts an URL's contents as forward-slash separated list of elements, received as parameters, e.g.
site.com/controller/method/var1/var2
has associated controller:
class Controller
function method(var1, var2){
}
}
But how can I achieve this coding? I wish to start with an array and send a parameterized list to a function, i.e.
$args = array("one"=>"cheese","two"=>"eggs");
php_function("myfunction",$args);
Within myfunction, I would have
function myfunction($one, $two){
}
I know about func_get_args for accepting an unknown number of arguments. user_call_func is useful except
user_call_func("myfunction",$args);
...results in the first parameter containing an array of arguments, no difference to func_get_args called from within the function.
extract doesn't work either as I need to receive the array as a variable inside the function.
call_user_func_array takes a method description and an array of arguments, and returns the result of calling the function. I think it will take the arguments from the array in order though, rather than by name. You should assemble an array of the arguments in the correct order, and perhaps validate for missing arguments, before using this.
I've managed to create your desired with the following.
class BootStrap {
private $controller = 'NameOfIle.php';
private $method = 'function()';
private $params = array('sdfds' => 'dsfdsf', 'sdfdsfsdfdsfsd' => 'sdfdsfds');
public function __construct() {
call_user_func_array(array($this->controller, $this->method), $this->params);
}
}

Call methods by defined names & add extra parameter before being called

I have a Validator class that can build several arrays with methods (names) stored.
Like so $this->rules[1] = ['trim()', 'required()', 'max(35)'];
How can I loop through every method the array and call it exactly by how they are defined?
If I do it like the following, I get Undefined property: Validator::$trim() etc. error.
foreach ($this->rules[1] as $method) {
$this->$method;
}
How can I add an extra parameter $input to each method in the array before it gets in the loop?
So instead of trim() it would be trim($input), and for max(35) max(35, $input), etc.
First of all, use $this->{$method} to call your method in your example.
Secondly, don't call them like that at all. Use call_user_func_array instead.
You need to extract method name and parameters frist in order to call directly.
I recommend you use a placeholder for your $input to add it to your method call.
You can then pass the parameters for your function call as an array.
$ruleset = 'max(34,:input)';
// do the string manipulation yourself please ;-)
$method = 'max';
$input = getInput(); // wherever you get that from
$parameters = array (34, $input),
call_user_func_array(__NAMESPACE__ .'\Validator::' . $method, $parameters);
What you are looking for are the call_user_func and/or call_user_func_array methods.
As Andresch pointed out, the way your rules are defined aren't flexible. Now you would have to parse them to retrieve the inputs for the function. a better way would be the following format:
$this->rules[1] = array(
'trim',
'required',
array('max'=>35)
);
and then
foreach ( $this->rules as $rule )
{
if ( is_array($rule)
{
call_user_func_array(array($this, key($rule)), current($rule));
}
else
{
call_user_func(array($this,$rule));
}
}
P.S. don't just copy paste this code, this is intended for explanation

Categories