Codeigniter template class: check if pseudo variables have a value - codeigniter

Not sure if it's possible, but can you use if statements inside a template?
So if a phone number does not have a value I don't want to display that sentence at all...
<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset="utf-8"/>
<title>{form_title}</title>
</head>
<body>
<p>You received the following message from {name} through the Gossip Cakes' contact form.</p>
<p>Their email is {email}</p>
<p>Their phone number is {phone}</p>
<p>The message: {message}</p>
</body>
</html>
I guess I could use straight php, but is there a method of returning the html of a view?

CI templates do have support for IF statements if you are creative. I use them frequently. You can even use them to prevent the template elements from being parsed if there is no data.
Consider these three example arrays:
$phone_numbers = array(
array('phone_number'=>'555-1212'),
array('phone_number'=>'555-1313')
)
$phone_numbers = array()
$phone_numbers = array( array('phone_number'=>'555-1414') )
And consider this is the relevant section in your html:
{phone_numbers} <p>{phone_number}</p> {phone_numbers}
Using the three arrays, the respective output arrays one and three are as follows. (Using array two would print nothing as the control array is empty.)
<p>555-1212</p><p>555-1313</p>
<p>555-1414</p>

Assuming you're using CI's built in parser, you have to prep all the variables beforehand. There is no support for conditions, variable assignment, or anything beyond loops and basic token replacement at this time.
To do this in CI, you'd have to prep the whole message, something like this in your controller:
if ($phone) {
$data['phone_msg'] = "<p>Their phone number is $phone</p>";
} else {
$data['phone_msg'] = '';
}
Not a good solution. Personally I'd recommend Twig if you're looking for a nice template parser. Your idea of "I guess I could use straight PHP" is also a very good one.
is there a method of returning the html of a view?
Use the third param of view() like so:
$html = $this->load->view('myview', $mydata, TRUE);
echo 'Here is the HTML:';
echo $html;
// OR...
echo $this->parser->parse_string($html, NULL, TRUE);

class MY_Parser extends CI_Parser{
/**
* Parse a template
*
* Parses pseudo-variables contained in the specified template,
* replacing them with the data in the second param,
* and clean the variables that have not been set
*
* #access public
* #param string
* #param array
* #param bool
* #return string
*/
function _parse($template, $data, $return = FALSE)
{
if ($template == '')
{
return FALSE;
}
foreach ($data as $key => $val)
{
if (is_array($val))
{
$template = $this->_parse_pair($key, $val, $template);
}
else
{
$template = $this->_parse_single($key, (string)$val, $template);
}
}
#$template = preg_replace('/\{.*\}/','',$template);
$patron = '/\\'.$this->l_delim.'.*\\'.$this->r_delim.'/';
$template = preg_replace($patron,'',$template);
if ($return == FALSE)
{
$CI =& get_instance();
$CI->output->append_output($template);
}
return $template;
}
}
Enjoy :D

Related

Joomla router.php links displayed correctly but doesnt works joomla 3.7

I have a problem with router.php
I cannot found an error in public function parse(&$segments)
The url generated as i want but it doesn't work with sef correct
the parse function gets correctly the view and the id_tsi parameters but id_tsi parameter seems to be not working
Version of joomla 3.7
the url of the component looks like
www.ktopoverit.ru/index.php?option=com_helloworld&view=reestr_si&id_tsi=1
url with switched on sef looks like
www.ktopoverit.ru/poverka/reestr_si/1
$vars looks like
Array (
[view] => reestr_si
[id_tsi] => 1
)
and my router is
class helloworldRouter extends JComponentRouterBase
{
public function build(&$query)
{
$segments = array();
if (isset($query['view']))
{
$segments[] = $query['view'];
unset($query['view']);
}
if (isset($query['id_tsi']))
{
$segments[] = $query['id_tsi'];
unset($query['id_tsi']);
};
return $segments;
}
public function parse(&$segments)
{
$vars = array();
switch($segments[0])
{
case 'reestr_si':
$vars['view'] = 'reestr_si';
$id = explode(':', $segments[0]);
$vars['id_tsi'] = (int) $id[1];
break;
}
return $vars;
}
}
Since your build() method creates the right URLs, it makes sense to take it as the base for some assumptions.
$query contains max. two values, a view (string) and an id (int). One or both of them may be omitted.
So. independent from the actual number of segments, we can just assume that an int represents the id and a string (i.e., everything else) represents the view.
/**
* Parse URL
*
* This method is meant to transform the human readable URL back into
* query parameters. It is only executed when SEF mode is switched on.
*
* #param array &$segments The segments of the URL to parse.
*
* #return array The URL attributes to be used by the application.
*/
public function parse(&$segments)
{
while (!empty($segments))
{
$segment = array_pop($segments);
if (is_numeric($segment))
{
// It's the ID
$vars['id_tsi'] = (int) $segment;
}
else
{
// It's the view
$vars['view'] = $segment;
}
}
return $vars;
}

codeigniter pagination - how to keep on same page after deleting row

I am using codeigniter pagination library and doing update and delete through form. The problem is when I delete or update any record after delete or update I redirected back to 1st page even if I am at 4th page. How I can redirected to the same page at which I have done update or delete.
Here is my controller code for update and delete functions:
public function update_att(){
if(isset($_POST['update'])){
$u_id = $_POST['at_id'];
if($_POST['status']=="Present"){
$data = array(
'status'=>"Absent"
);
$this->db->where('at_id', $u_id);
$this->db->update('attendence', $data);
}elseif ($_POST['status']=="Absent") {
$data = array(
'status'=>"Present"
);
$this->db->where('at_id', $u_id);
$this->db->update('attendence', $data);
}
redirect("usr/att_list", "refresh");
}
}
public function delete_att(){
if (isset($_POST['delete'])) {
$at_id = $_POST['at_id'];
$this->db->where('at_id', $at_id);
$this->db->delete('attendence');
}
redirect("usr/att_list" );
}
Currently I am redirecting to the first page , any suggestion how I redirect to that page where I have done delete or update.
Add <input type='hidden' name='current_page' value='<?php echo $current_page?>' /> to your form.
Keep in mind you need to populate $current_page with something like
$current_page = ''; // empty means first page
if( isset($_REQUEST['current_page'] ){
$current_page = $_REQUEST['current_page'];
}
Then based on your sample you just modifiy the redirect path as follows (for both your functions):
public function delete_att(){
if (isset($_POST['delete'])) {
$at_id = $_POST['at_id'];
$this->db->where('at_id', $at_id);
$this->db->delete('attendence');
}
redirect("usr/att_list".(strlen($current) ? "?".$current : "" );
}
Note:
Your path to your page should look something like this domain.com/controller/your_page_with_pagination/?current_page=A_NUMBER then in your controller/your_page_with_pagination you adjust the data you wish to output based on $_GET['current_page']
Edit based on your link:
public function att_list($id = ""){
/**
* Keep your data in array
*/
$this->data = array();
/**
* Add the page number ($id) to the array
* Check for url /:id first , or else check for a $_GET/$_POST current_page (this will be triggered when you submit your form)
*/
$this->data['current_page'] = is_numeric($id) ? $id : (isset($_REQUEST['current_page'] ? $_REQUEST['current_page']: 0);
/**
* This is your 'keep on the same page' line
* $this->data['current_page'] will act as an offset in your query
* You can read about 'offset' here https://www.w3schools.com/php/php_mysql_select_limit.asp
* $this->data['my_desired_records'] must be generated into your <form> ... </form> , and the same form must contain the input with name='current_page'
*/
$this->data['my_desired_records'] = $this->your_model->get_data($this->data['current_page']);
/**
* Pass the whole array into your view
*/
$this->load->view('path/to/view', $this->data);
}
Then in your view add in your form <input type='hidden' name='current_page' value='<?php echo $this->data['current_page']?>' />

How to specify fields for $plus->people->get('me') call?

With Google API PHP client library I use the following code, which works well and prints lot of information about the user, who authorizes my application via OAuth2:
<?php
require_once('google-api-php-client-1.1.7/src/Google/autoload.php');
const TITLE = 'My amazing app';
const REDIRECT = 'https://example.com/myapp/';
session_start();
$client = new Google_Client();
$client->setApplicationName(TITLE);
$client->setClientId('REPLACE_ME.apps.googleusercontent.com');
$client->setClientSecret('REPLACE_ME');
$client->setRedirectUri(REDIRECT);
$client->setScopes(array(Google_Service_Plus::PLUS_ME));
$plus = new Google_Service_Plus($client);
if (isset($_REQUEST['logout'])) {
unset($_SESSION['access_token']);
}
if (isset($_GET['code'])) {
if (strval($_SESSION['state']) !== strval($_GET['state'])) {
error_log('The session state did not match.');
exit(1);
}
$client->authenticate($_GET['code']);
$_SESSION['access_token'] = $client->getAccessToken();
header('Location: ' . REDIRECT);
}
if (isset($_SESSION['access_token'])) {
$client->setAccessToken($_SESSION['access_token']);
}
if ($client->getAccessToken() && !$client->isAccessTokenExpired()) {
try {
$me = $plus->people->get('me'); # HOW TO SPECIFY FIELDS?
$body = '<PRE>' . print_r($me, TRUE) . '</PRE>';
} catch (Google_Exception $e) {
error_log($e);
$body = htmlspecialchars($e->getMessage());
}
# the access token may have been updated lazily
$_SESSION['access_token'] = $client->getAccessToken();
} else {
$state = mt_rand();
$client->setState($state);
$_SESSION['state'] = $state;
$body = sprintf('<P>Login</P>',
$client->createAuthUrl());
}
?>
<!DOCTYPE HTML>
<HTML>
<HEAD>
<TITLE><?= TITLE ?></TITLE>
</HEAD>
<BODY>
<?= $body ?>
<P>Logout</P>
</BODY>
</HTML>
However I need less info than returned by the above script.
When entering just the fields I am interested in at the People: get "API explorer":
id,gender,name,image,placesLived
this again works well and prints only the specified fields:
MY QUESTION:
How to specify the fields in the above $me = $plus->people->get('me'); call?
After studying 1.1.7/src/Google/Service/Plus.php with the code:
/**
* Get a person's profile. If your app uses scope
* https://www.googleapis.com/auth/plus.login, this method is
* guaranteed to return ageRange and language. (people.get)
*
* #param string $userId The ID of the person to get the profile for. The
* special value "me" can be used to indicate the authenticated user.
* #param array $optParams Optional parameters.
* #return Google_Service_Plus_Person
*/
public function get($userId, $optParams = array())
{
$params = array('userId' => $userId);
$params = array_merge($params, $optParams);
return $this->call('get', array($params), "Google_Service_Plus_Person");
}
I have tried the following PHP code:
const FIELDS = 'id,gender,name,image,placesLived';
$me = $plus->people->get('me', array('fields' => urlencode(FIELDS)));
but for some reason it prints a lot of :protected strings:
Google_Service_Plus_Person Object
(
[collection_key:protected] => urls
[internal_gapi_mappings:protected] => Array
(
)
[aboutMe] =>
[ageRangeType:protected] => Google_Service_Plus_PersonAgeRange
[ageRangeDataType:protected] =>
[birthday] =>
[braggingRights] =>
[circledByCount] =>
[coverType:protected] => Google_Service_Plus_PersonCover
[coverDataType:protected] =>
[currentLocation] =>
[displayName] =>
[domain] =>
[emailsType:protected] => Google_Service_Plus_PersonEmails
[emailsDataType:protected] => array
[etag] =>
[gender] => male
...
Also I have tried just appending the fields after me:
$me = $plus->people->get('me?fields=' . urlencode(FIELDS)));
but get the 404 error:
Error calling GET
https://www.googleapis.com/plus/v1/people/me%3Ffields%3Did%252Cgender%252Cname%252Cimage%252CplacesLived:
(404) Not Found
UPDATE: I have created Issue #948 at GitHUb.
To specify which fields to get from the G+ API, you just have to specify a fields member in the options array. So actually you got very close to the solution:
$me = $plus->people->get('me', array('fields' => 'id,gender,name,image,placesLived'));
You don't even have to urlencode, as it is a default safety feature of the library itself.
The thing that might have tricked you is, that the Google_Service_Plus_Person class contains all the possible fields a protected members, not regarding the actual fields that were sent by the API. Not included fields will be empty in the object. As always, protected members should not be used in any way by the user of the class.
You, as the user of the library should only use public members, such as $me->getPlacesLived() and $me->getId(). Dumping whole objects is a nice tool during development, but in production calling the public interface is the way to go.

Validation of array form fields in laravel 4 error

How can we validate form fields that are arrays? Take a look at the following code
UserPhone Model:
public static $rules= array(
'phonenumber'=>'required|numeric',
'isPrimary'=>'in:0,1'
)
...........
UserController:
$validation = UserPhone::validate(Input::only('phonenumber')));
if($validation->passes())
{
$allInputs = Input::only('phonenumber','tid');
$loopSize = sizeOf($allInputs);
for($i=0;$i<$loopSize;$i++)
{
$phone = UserPhone::find($allInputs['tid'][$i]);
$phone->phonenumber = $allInputs['phonenumber'][$i];
$phone->save();
}
return Redirect::to('myprofile')->with('message','Update OK');
}
else
{
return Redirect::to('editPhone')->withErrors($validation);
}
}
the $validation comes from a BaseModel which extends Eloquent.
In my view:
<?php $counter=1; ?>
#foreach($phones as $thephone)
<section class="col col-12">
<label class="label">Phone Number {{$counter++}}</label>
<label class="input">
<i class="icon-append icon-phone"></i>
{{Form::text('phonenumber[]',$thephone->phonenumber)}}
{{Form::hidden('tid[]',$thephone->id)}}
</label>
</section>
#endforeach
Everything is working fine and I get all the phone numbers I want in the Update Form, but I cannot update the model because the validation fails with the message "Phonenumber must be a number".
I know that there is not a simple solution for validating array form fields and I tried to extend the validator class but with no success.
How can I validate this kind of fields?
Here's the solution I use:
Usage
Simply transform your usual rules by prefixing each. For example:
'names' => 'required|array|each:exists,users,name'
Note that the each rule assumes your field is an array, so don't forget to use the array rule before as shown here.
Error Messages
Error messages will be automatically calculated by the singular form (using Laravel's str_singular() helper) of your field. In the previous example, the attribute is name.
Nested Arrays
This method works out of the box with nested arrays of any depth in dot notation. For example, this works:
'members.names' => 'required|array|each:exists,users,name'
Again, the attribute used for error messages here will be name.
Custom Rules
This method supports any of your custom rules out of the box.
Implementation
1. Extend the validator class
class ExtendedValidator extends Illuminate\Validation\Validator {
public function validateEach($attribute, $value, $parameters)
{
// Transform the each rule
// For example, `each:exists,users,name` becomes `exists:users,name`
$ruleName = array_shift($parameters);
$rule = $ruleName.(count($parameters) > 0 ? ':'.implode(',', $parameters) : '');
foreach ($value as $arrayKey => $arrayValue)
{
$this->validate($attribute.'.'.$arrayKey, $rule);
}
// Always return true, since the errors occur for individual elements.
return true;
}
protected function getAttribute($attribute)
{
// Get the second to last segment in singular form for arrays.
// For example, `group.names.0` becomes `name`.
if (str_contains($attribute, '.'))
{
$segments = explode('.', $attribute);
$attribute = str_singular($segments[count($segments) - 2]);
}
return parent::getAttribute($attribute);
}
}
2. Register your validator extension
Anywhere in your usual bootstrap locations, add the following code:
Validator::resolver(function($translator, $data, $rules, $messages)
{
return new ExtendedValidator($translator, $data, $rules, $messages);
});
And that's it! Enjoy!
Bonus: Size rules with arrays
As a comment pointed out, there's seems to be no easy way to validate array sizes. However, the Laravel documentation is lacking for size rules: it doesn't mention that it can count array elements. This means you're actually allowed to use size, min, max and between rules to count array elements.
It works best to extend the Validator class and re-use the existing Validator functions:
Validator::resolver(function($translator, $data, $rules, $messages)
{
return new Validation($translator, $data, $rules, $messages);
});
class Validation extends Illuminate\Validation\Validator {
/**
* Magically adds validation methods. Normally the Laravel Validation methods
* only support single values to be validated like 'numeric', 'alpha', etc.
* Here we copy those methods to work also for arrays, so we can validate
* if a value is OR an array contains only 'numeric', 'alpha', etc. values.
*
* $rules = array(
* 'row_id' => 'required|integerOrArray', // "row_id" must be an integer OR an array containing only integer values
* 'type' => 'inOrArray:foo,bar' // "type" must be 'foo' or 'bar' OR an array containing nothing but those values
* );
*
* #param string $method Name of the validation to perform e.g. 'numeric', 'alpha', etc.
* #param array $parameters Contains the value to be validated, as well as additional validation information e.g. min:?, max:?, etc.
*/
public function __call($method, $parameters)
{
// Convert method name to its non-array counterpart (e.g. validateNumericArray converts to validateNumeric)
if (substr($method, -7) === 'OrArray')
$method = substr($method, 0, -7);
// Call original method when we are dealing with a single value only, instead of an array
if (! is_array($parameters[1]))
return call_user_func_array(array($this, $method), $parameters);
$success = true;
foreach ($parameters[1] as $value) {
$parameters[1] = $value;
$success &= call_user_func_array(array($this, $method), $parameters);
}
return $success;
}
/**
* All ...OrArray validation functions can use their non-array error message counterparts
*
* #param mixed $attribute The value under validation
* #param string $rule Validation rule
*/
protected function getMessage($attribute, $rule)
{
if (substr($rule, -7) === 'OrArray')
$rule = substr($rule, 0, -7);
return parent::getMessage($attribute, $rule);
}
}
each()
It's not in the docs, but the 4.2 branch may have a simple solution around line 220.
Just like the sometimes($attribute, $rules, callable $callback) function, there is now an each($attribute, $rules) function.
To use it, the code would be something simpler than a sometimes() call:
$v->each('array_attribute',array('rule','anotherRule')); //$v is your validator
Caveats
sometimes() and each() don't seem to be easily chainable with each other so if you want to do specifically conditioned rules on array values, you're better off with the magic solutions in other answers for now.
each() only goes one level deep which isn't that different from other solutions. The nice thing about the magic solutions is that they will go 0 or 1 level deep as needed by calling the base rules as appropriate so I suppose if you wanted to go 1 to 2 levels deep, you could simply merge the two approaches by calling each() and passing it a magic rule from the other answers.
each() only takes one attribute, not an array of attributes as sometimes() does, but adding this feature to each() wouldn't be a massive change to the each() function - just loop through the $attribute and array_merge() $data and the array_get() result. Someone can make it a pull request on master if they see it as desirable and it hasn't already been done and we can see if it makes it into a future build.
Here's an update to the code of Ronald, because my custom rules wouldn't work with the array extension. Tested with Laravel 4.1, default rules, extended rules, …
public function __call($method, $parameters) {
$isArrayRule = FALSE;
if(substr($method, -5) === 'Array') {
$method = substr($method, 0, -5);
$isArrayRule = TRUE;
}
//
$rule = snake_case(substr($method, 8));
// Default or custom rule
if(!$isArrayRule) {
// And we have a default value (not an array)
if(!is_array($parameters[1])) {
// Try getting the custom validation rule
if(isset($this->extensions[$rule])) {
return $this->callExtension($rule, $parameters);
}
// None found
throw new \BadMethodCallException("Method [$method] does not exist.");
} // Array given for default rule; cannot be!
else return FALSE;
}
// Array rules
$success = TRUE;
foreach($parameters[1] as $value) {
$parameters[1] = $value;
// Default rule exists, use it
if(is_callable("parent::$method")) {
$success &= call_user_func_array(array($this, $method), $parameters);
} else {
// Try a custom rule
if(isset($this->extensions[$rule])) {
$success &= $this->callExtension($rule, $parameters);
}
// No custom rule found
throw new \BadMethodCallException("Method [$method] does not exist.");
}
}
// Did any of them (array rules) fail?
return $success;
}
There are now array validation rules in case this helps anybody. It doesn't appear that these have been written up in the docs yet.
https://github.com/laravel/laravel/commit/6a2ad475cfb21d12936cbbb544d8a136fc73be97

KO3 - Kohana 3 - How can I pass $_POST data from a controller/action back to the view/form that called it?

I am trying to validate a form submission in Kohana 3. I have the form::open point to my action_create in my controller which successfully validates the data posted to it from the form in my view. If the data passes validation, a new item is created as intended, and the user is redirected to the item that was just created. This works correctly. If the data fails validation, however, I would like the user to be directed back to the originating view/page while retaining a variable containing the data that was posted so that I can repopulate the form and display errors.
In short, how can I pass data from a view -> controller -> original view?
Thank you, everyone!
The user also posed this question on the Kohana forums.
Those seeking an answer to this should have look over there.
I assume you're using Controller_Template.
File views/form.php:
// Set default variables if variables not passed to this view
$username = isset($username) ? $username : '';
echo Form::open('login');
// Input: username
echo Form::label('username', 'Username');
echo Form::input('username', $username);
echo isset($errors['username']) ? $errors['username'] : '';
// Input: username
echo Form::label('password', 'Password');
echo Form::input('password', $password);
echo isset($errors['password']) ? $errors['password'] : '';
echo Form::close();
File views/template.php
<html>
<head><title>My Website</title></head>
<body>
<?php echo isset($content) ? $content : ''; ?>
</body>
</html>
File classes/controller/user.php
Class Controller_User extends Controller_Template {
public $template = 'template';
public function index()
{
$this->template->content = $this->display_form('form');
}
public function login()
{
// Setup validation & rules here
// Check validation, assume $validation is Validation object
if ($validation->check()
{
// Validation succeeded. Do anything you want here
}
else
{
// Validation failed. Display form with entered values
$form_vars = $_POST;
$form_vars['errors'] = $validation->errors();
// Display form
$this->template->content = $this->display_form('form', $form_vars);
}
}
// Displaying form
private function display_form($form_file, $form_vars=NULL)
{
$form = View::factory($form_file);
if ($form_vars != NULL)
{
foreach($form_vars as $key => $value)
{
$form->$key = $value;
}
}
return $form;
}
}
Hope that helps!

Resources