I have a main view in my CI app in which I declare a variable.
That main view loads several subview in a loop.
I would like these subviews to modify my variable so that at the end of the loop its value would be updated.
Example:
main_view.php
<?php
$my_var = false;
foreach($a_views as $s_view){
$this->load->view($s_view, array('my_var' => $my_var);
}
var_dump($my_var); // Still false
?>
sub_view.php
<?php $my_var = true; ?>
Check out the code for the $this->load->view function.
The data you pass to the view is "one-way" which means it's available and can be modified only in the view itself.
Which means you'll have to find another way to achieve what you're trying to achieve.
Keep in mind that according to what I've understood from your question you're trying to have some "logical manipulation" using "views" which is kind of breaking the MVC architecture.
/**
* View Loader
*
* Loads "view" files.
*
* #param string $view View name
* #param array $vars An associative array of data
* to be extracted for use in the view
* #param bool $return Whether to return the view output
* or leave it to the Output class
* #return object|string
*/
public function view($view, $vars = array(), $return = FALSE)
{
return $this->_ci_load(array('_ci_view' => $view, '_ci_vars' => $this->_ci_prepare_view_vars($vars), '_ci_return' => $return));
}
Related
After fundamental changes on my project system architecture, I find myself in a situation where I would need to create "fake" implementation in order to test some functionality that used to be public like the following:
/**
* Display the template linked to the page.
*
* #param $newSmarty Smarty object to use to display the template.
*
* #param $parameters associative Array containing the values to pass to the template.
* The key is the name of the variable in the template and the value is the value of the variable.
*
* #param $account child class in the AccountManager hierarchy
*
* #param $partialview String name of the partial view we are working on
*/
protected function displayPageTemplateSmarty(Smarty &$newSmarty, array $parameters = array(), AccountManager $account = NULL, string $partialview = "")
{
$this->smarty = $newSmarty;
if (is_file(
realpath(dirname(__FILE__)) . "/../../" .
Session::getInstance()->getCurrentDomain() . "/view/" . (
!empty($partialview) ?
"partial_view/" . $partialview :
str_replace(
array(".html", "/"),
array(".tpl", ""),
Session::getInstance()->getActivePage()
)
)
)) {
$this->smarty->assign(
'activeLanguage',
Session::getInstance()->getActiveLanguage()
);
$this->smarty->assign('domain', Session::getInstance()->getCurrentDomain());
$this->smarty->assign(
'languages',
Languagecontroller::$supportedLanguages
);
$this->smarty->assign(
'title',
Languagecontroller::getFieldTranslation('PAGE_TITLE', '')
);
$this->smarty->assign_by_ref('PageController', $this);
$htmlTagBuilder = HTMLTagBuilder::getInstance();
$languageController = LanguageController::getInstance();
$this->smarty->assign_by_ref('htmlTagBuilder', $htmlTagBuilder);
$this->smarty->assign_by_ref('languageController', $languageController);
if (!is_null($account)) {
$this->smarty->assign_by_ref('userAccount', $account);
}
if (!is_null($this->menuGenerator)) {
$this->smarty->assign_by_ref('menuGenerator', $this->menuGenerator);
}
foreach ($parameters as $key => $value) {
$this->smarty->assign($key, $value);
}
$this->smarty->display((!empty($partialview) ?
"partial_view/" . $partialview :
str_replace(
array(".html", "/"),
array(".tpl", ""),
Session::getInstance()->getActivePage()
)
));
}
}
In this case, the PageController class used to be called directly in controllers, but is now an abstract class extended by the controllers and my unit tests can no longer access the method.
I also have methods like this one in my new session wrapper class that can only be used in very specific context and for which I really need to create fake page implementation to test them.
/**
* Add or update an entry to the page session array.
*
* Note: can only be updated by the PageController.
*
* #param $key String Key in the session array.
* Will not be added if the key is not a string.
*
* #param $value The value to be added to the session array.
*
* #return Boolean
*/
public function updatePageSession(string $key, $value)
{
$trace = debug_backtrace();
$updated = false;
if (isset($trace[1]) and
isset($trace[1]['class']) and
$trace[1]['class'] === 'PageController'
) {
$this->pageSession[$key] = $value;
$updated = true;
}
return $updated;
}
Even though I read a few article, it is still quite unclear in my mind if those fake classes should be considered as "stub" or a "mock" (or even "fake", "dummy" and so on).
I really need to use the proper terminology since my boss is expecting me (in a close future) to delegate most of my workload with oversea developers.
How would you call those fake class implementation created solely for testing purpose in order to be self-explanatory?
Gerard Meszaros explains the terminology of dummies, stubs, spies, mocks, and fakes here.
You can find examples from the PHP world here.
Does anyone know whether there is a setting in PhpStorm that can trigger identifying variables generated using extract() function?
Example would be something like the following:
/**
* #return array
*/
protected function orderSet() : array
{
//...
return [
'colour' => $colour,
'green' => $green,
'orange' => $orange
];
}
/**
* #test
*/
public function returns_correct_attribute_names()
{
$params = $this->orderSet();
extract($params);
$this->assertEquals(
'Colour',
$colour->name
);
}
At the moment any variable that's been extracted in the test is highlighted (unrecognised), but perhaps there is a setting that can change this behaviour?
The solution that LazyOne offered actually works. However there is a bit more context you need in order to implement it.
To accurately inform PHPSTORM about the variables you want to declare the comment must be placed directly above extract() and not the parent function.
public function db(){
$db = new SQLite3('db/mysqlitedb.db');
$payments = $db->query('SELECT * FROM payments');
while ($pay = $payments->fetchArray()){
/**
* #var string $to_user
* #var string $from_user
* #var number $amount
*/
extract($pay);
if (isset($to_user, $from_user, $amount))
echo "TO: {$to_user}| FROM: {$from_user}| $ {$amount} \n";
};
}
This is a working sample from my code ( couldn't copy yours for some reason ).
You can see just before I use the extract() function I declare in the comment block above it the hidden variables and data types.
Bonus: if you intend to use extract, I highly recommend you use an isset to ensure the array you're parsing contains the fields you are expecting.
example in code above
I'm trying to debug some old code from CodeIgniter 2.2. When running some data thru Session, I noticed an unserialize error, Message: unserialize(): Error at offset 160 of 163 bytes. After doing some debugging and research, I found out it's a common backslash issue when unserializing data from Sessions.
The serialized data I'm using has objects of data with backslashes in them, which causes the errors to occur. I'm in need of a replacement that can handle standard class objects as well.
Could someone recommend a quick replacement for codeigniter's Session _serialize() and _unserialize() methods?
public function data_test() {
$input = array(
(object)array('name' => 'test2', 'desc' => 'bla bla ob/gyn'),
(object)array('name' => 'test2', 'desc' => 'bla bla ob\\gyn'),
);
var_dump($input);
$data = $this->_serialize($input);
var_dump($data);
$result = $this->_unserialize($data);
var_dump($result);
}
// --------------------------------------------------------------------
/**
* Serialize an array
*
* This function first converts any slashes found in the array to a temporary
* marker, so when it gets unserialized the slashes will be preserved
*
* #access private
* #param array
* #return string
*/
function _serialize($data) {
if (is_array($data)) {
foreach ($data as $key => $val) {
if (is_string($val)) {
$data[$key] = str_replace('\\', '{{slash}}', $val);
}
}
} else {
if (is_string($data)) {
$data = str_replace('\\', '{{slash}}', $data);
}
}
return serialize($data);
}
// --------------------------------------------------------------------
/**
* Unserialize
*
* This function unserializes a data string, then converts any
* temporary slash markers back to actual slashes
*
* #access private
* #param array
* #return string
*/
function _unserialize($data) {
$data = unserialize(strip_slashes($data));
if (is_array($data)) {
foreach ($data as $key => $val) {
if (is_string($val)) {
$data[$key] = str_replace('{{slash}}', '\\', $val);
}
}
return $data;
}
return (is_string($data)) ? str_replace('{{slash}}', '\\', $data) : $data;
}
/**
* Serialize an array
*
* This function serializes the data and then base64_encodes it for
* storage with memcached. This avoids the common backslash issue.
*
* #access private
* #param array
* #return string
*/
function _serialize($data) {
return base64_encode(serialize($data));
}
// --------------------------------------------------------------------
/**
* Unserialize
*
* This function unserializes a data string. I first base64_decodes
* the data from memcached storage.
*/
function _unserialize($data) {
return unserialize(base64_decode($data));
}
You can sometimes come across this issue if you are using different versions of PHP, or if you change the version of PHP you are using while a session was open.
For example if you have a session cookie with an app that uses PHP 5.6.* and then you try to use it with an app (that resides on another sub-domain) that uses PHP 7.2.*, then you are going to get a warning error. Or, if you had an open session and then you changed the version of PHP that you are using with your app (say if you are developing locally and switching around PHP versions), then you'll get the warning. So best to use serialize/unserialize and with PHP version that does not change.
So I decided to go from Laravel 4 to 5 which took me around 1-2 days because I barely knew how to do the transition. While doing the Upgrade for my app i came across a small problem with Json Pagination.
This code is what allows a PageQuery to be Paginated Via KnockoutJS
/**
* Builds paginate query with given parameters.
*
* #param array $params
* #param integer $page
* #param integer $perPage
*
* #return array
*/
public function buildPaginateQuery(array $params, $page = 1, $perPage = 15)
{
$query = $this->model;
$query = $this->appendParams($params, $query);
$count = (new Cache)->remember('count', '2000', function() use ($query){
return $query->count();
});
$totalPages = $count / $perPage;
$query = $query->skip($perPage * ($page - 1))->take($perPage);
$query = $query->order(isset($params['order']) && $params['order'] ? $params['order'] : null);
//$query = $query->cacheTags(array($this->model->table, 'pagination'))->remember(2000);
$query = (new Cache)->remember(array($this->model->table, 'pagination'), '2000', function() use ($query){
return $query;
});
return array('query' => $query, 'totalPages' => $totalPages, 'totalItems' => $count);
}
which eventually lead to this error in this screenshot
The Error directs to the code above and this code specifically
/**
* Get the full path for the given cache key.
*
* #param string $key
* #return string
*/
protected function path($key)
{
$parts = array_slice(str_split($hash = md5($key), 2), 0, 2);
$path = $this->directory() . '/'.join('/', $parts).'/'.$hash;
//unset the tags so we use the base cache folder if no
//tags are passed with subsequent call to the same instance
//of this class
//$this->tags = array();
return $path;
}
Im using a custom Cache Driver called TaggedFile. This worked fine in L4 but came across errors because There were some files removed within the Cache Alias. Like the StoreInterface. Can I receive some help for this? If you need me to post anything I will.
More Stuff:
Before I used this to Register the taggedFile Driver in global.php:
Cache::extend('taggedFile', function($app)
{
return new Illuminate\Cache\Repository(new Lib\Extensions\TaggedFileCache);
});
I do not know where exactly to put this. Does anyone know the equivalent of that? I tried putting it in AppServiceProvider but an error came up saying:
Call to undefined method Illuminate\Support\Facades\Cache::extend()
This used to work in L4 so i decided to go into the vendor folder manually find what the problem was....
This only had: getFacadeAccessor (Which L4 also only had but extend worked)
So i decided to use getFacadeAccessor and it worked, but i don't know if that was the solution or not.
As you noticed you are passing an array as a $key value, the safest way would be to replace the code
$parts = array_slice(str_split($hash = md5($key), 2), 0, 2);
With
$parts = array_slice(str_split($hash = md5(json_encode($key)), 2), 0, 2);
NB: I am not sure what version of php you are running, but json_encode( ... ) is normally faster then serialize( ... )
I am wondering this question for a long time, how does PHP handle references are they a good idea to use and I can't explain better than using an example, lets look at the following class and then # the comment of the setResult method.
Lets imagine we are using a model view controller framework and we are building a basic AjaxController, we only got 1 action method (getUsers) so far. Read the comments, and I hope my question is clear, how does PHP handle these kind of situations and is it true what I wrote about the x times in the memory # the setResult docblock.
class AjaxController{
private $json = array(
'result' => array(),
'errors' => array(),
'debug' => array()
);
/**
* Adds an error, always displayed to users if any errors.
*
* #param type $description
*/
private function addError($description){
$this->json['errors'][] = $description;
}
/**
* Adds an debug message, these are displayed only with DEBUG_MODE.
*
* #param type $description
*/
private function addDebug($description){
$this->json['debug'][] = $description;
}
/**
* QUESTION: How does this go in memory? Cause if I use no references,
* the array would be 3 times in the memory, if the array is big (5000+)
* its pretty much a waste of resources.
*
* 1st time in memory # model result.
* 2th time in memory # setResult ($resultSet variable)
* 3th time in memory # $this->json
*
* #param array $resultSet
*/
private function setResult($resultSet){
$this->json['result'] = $resultSet;
}
/**
* Gets all the users
*/
public function _getUsers(){
$users = new Users();
$this->setResult($users->getUsers());
}
public function __construct(){
if(!DEBUG_MODE && count($this->json['debug']) > 0){
unset($this->json['debug']);
}
if(count($this->json['errors']) > 0){
unset($this->json['errors']);
}
echo json_encode($this->json);
}
}
Another simple example: What would be better to use technique A:
function example(){
$latestRequest = $_SESSION['abc']['test']['abc'];
if($latestRequest === null){
$_SESSION['abc']['test']['abc'] = 'test';
}
}
Or technique B:
function example(){
$latestRequest =& $_SESSION['abc']['test']['abc'];
if($latestRequest === null){
$latestRequest = 'test';
}
}
Thanks for reading and advise :)
In short: don't use references.
PHP copies on write. Consider:
$foo = "a large string";
$bar = $foo; // no copy
$zed = $foo; // no copy
$bar .= 'test'; // $foo is duplicated at this point.
// $zed and $foo still point to the same string
You should only use references when you need the functionality that they provide. i.e., You need to modify the original array or scalar via a reference to it.