If I configure Twig's cache to myapp/storage/cache and manually set the correct permissions it works, but configuring it to sys_get_temp_dir() (which returns /tmp) doesn't seem to work. File structure in /tmp remains the same, altough no error is triggered.
My block of code is like this:
// [...]
$app->register(new \Silex\Provider\TwigServiceProvider(), array(
'twig.path' => __DIR__ . '/templates',
'twig.options' => array(
'cache' => sys_get_temp_dir(), // If changed to myapp/storage/cache, it works.
),
));
I don't know if this can help you, but it is possible to override the default writeCacheFile method of the Twig_Environment. By doing so you can create the temporary folder yourself and apply the wanted permissions, so your user don't have to do this themself.
Custom Twig_Env
class Environment extends \Twig_Environment {
protected function writeCacheFile($file, $content){
createDirectoryTree(dirname($file));
parent::writeCacheFile($file, $content);
chmod($file,0664);
chgrp($file, 'psacln');
chown($file, 'www-data');
}
}
Functions.php
function createDirectoryTree($folder) {
if (is_dir($folder)) return;
$folder = str_replace('/', DIRECTORY_SEPARATOR, $folder);
$branches = explode(DIRECTORY_SEPARATOR, $folder);
$tree = '';
$old_mask = umask(0);
while(!empty($branches)) {
$tree .= array_shift($branches).DIRECTORY_SEPARATOR;
if (!#file_exists($tree)) {
if (#mkdir($tree, 0774)){
chown($tree, 'www-data');
chgrp($tree, 'psacln');
}
}
}
umask($old_mask);
}
Related
How can we setup multiple themes in codeigniter as in Magento?
I want to do this in HMVC CI.
I want to add theming feature with my development. I am using HMVC setup from Codeigniter HMVC
This is properly set and works fine.
This is a great development approach.
Here I am trying to add theme feature with this code, that could be controlled from admin panel.
/themes/themeName/templates/
/themes/themeName/modulesName/View
Approach is if view file not found in themes folder, it should come from
application/modules/moduleName.
What changes I have to do with this script ?
Can anyone suggest me what modification nee to do with this code?
Perhaps I misunderstood but why not extend CI's Loader class and add a theme function? I did this recently and it works great.
public function theme($view, $theme, $vars = array(), $return = FALSE) {
// Check if extension was specified. If not, add .php
$ext = pathinfo(APPPATH . $theme, PATHINFO_EXTENSION);
$view_file = ($ext == '') ? $view.'.php' : $view;
// Verify whether or not the requested theme file exists and set the template directory path prefix accordingly
if(file_exists(APPPATH . "views/store/theme/$theme/$view_file")) {
$this->_ci_view_paths = array(APPPATH . "views/store/theme/$theme/" => true);
}
else {
$this->_ci_view_paths = array(APPPATH . "views/store/theme/default/" => true);
}
return $this->_ci_load(array('_ci_view' => $view, '_ci_vars' => $this->_ci_object_to_array($vars), '_ci_return' => $return));
}
The following code works and does what I want, but I'm pretty sure I'm doing something dumb\awful.
I'm learning OOP and there is a tutorial I started to follow that used a "Config" class to setup some parameters for the program to use. I've noticed something similar in other tutorials. This tutorial though only included a method to retrieve the configuration (it used the $GLOBALS array) not to update it during the run time of the program. I attempted to add this functionality, but resorted to using eval() which I think is a nono? Also it was never explained in the tutorial why the $GLOBALS array was used instead of just using a static variable so I'm confused about that as well.
Here is init.php which gets included in files needing to access the config options:
<?php
$GLOBALS['config'] = array(
'mysql' => array(
'host' => '127.0.0.1',
'username' => 'root',
'password' => '123456',
'db' => NULL
),
'shell' => array(
'exe' => 'powershell.exe',
'args' => array(
'-NonInteractive',
'-NoProfile',
'-NoLogo',
'-Command'
)
)
);
spl_autoload_register(function($class){
require_once 'classes/' . $class . '.php';
});
This is the Config.php class which has a get and (my) set method to access the config array. For the set method I build a string like "$GLOBALS['config']['someConfig']['someSubConfig'] = 'newVal';" and use eval to execute it. Ultimately I use it in the program like Config::set('mysql/host','zzzzz');
<?php
class Config {
public static function get($path=NULL) {
//return all configs if not specified
$config = $GLOBALS['config'];
if($path) {
//parse path to return config
$path = explode('/', $path);
foreach($path as $element) {
if(isset($config[$element])) {
$config = $config[$element];
} else {
//if config not exist
$config = false;
}
}
}
return $config;
}
public static function set($path=NULL,$value=NULL) {
if($path) {
//parse path to return config
$path = explode('/', $path);
//Start code string for eval
$globalPosition = '$GLOBALS['."'config'".']';
foreach($path as $element) {
$globalPosition .= "['$element']";
}
$globalPosition .= "='$value';";
//End code string
eval($globalPosition);
var_dump($GLOBALS);
}
}
}
First of all, here are a few caveats:
Global variables are rarely a good idea, especially in OOP design (mainly because they couple code very tightly).
Please don't use eval().
You can quite easily modify your code to set the variable (by reference using =&) without having to use eval() at all. For example:
public static function set($path = null,$value = null)
{
if($path)
{
//parse path to return config
$path = explode('/', $path);
//Start code string for eval
$setting =& $GLOBALS['config'];
foreach($path as $element)
{
$setting =& $setting[$element];
}
$setting = $value;
var_dump($GLOBALS);
}
}
Normally I use the Zend Framework and this is something I miss in Lithium. Partials. There is a render method in the view where you can use 'elements' which is the closest I got.
<?php $this->_render('element', 'form); ?>
This does work, however it requires that the form.html.php file is in the /views/elements folder. Is it possible to let it search in another path? Like /views/users/ so it gets the file /views/users/form.html.php.
I have tried the following, since I found out that the render method does accept an options argument wherein you can specify a path. So I made an Helper to fix this problem for me.
namespace app\extensions\helper;
use lithium\template\TemplateException;
class Partial extends \lithium\template\Helper
{
public function render($name, $folder = 'elements', $data = array())
{
$path = LITHIUM_APP_PATH . '/views/' . $folder;
$options['paths']['element'] = '{:library}/views/' . $folder . '/{:template}.{:type}.php';
return $this->_context->view()->render(
array('element' => $name),
$data,
$options
);
}
}
However it still only searches in the /view/elements folder, not in the path I specified.
Is there something I am doing wrong?
Why using plugins when this stuff can hopefully be done by Lithium :-)
I don't know Zend, but here is an exemple to configure elements default paths differently, to load them from the related view folder, instead of a shared path.
And let's add one more thing: we want to differentiate elements/partials from a normal view, by appending un underscore to the name of the file (mimic Rails partials)
First, reconfigure Media during the bootstrap process (config/bootstrap/media.php)
Media::type('default', null, array(
'view' => 'lithium\template\View',
'paths' => array(
'layout' => '{:library}/views/layouts/{:layout}.{:type}.php',
'template' => '{:library}/views/{:controller}/{:template}.{:type}.php',
'element' => array(
'{:library}/views/{:controller}/_{:template}.{:type}.php',
'{:library}/views/elements/{:template}.{:type}.php'
)
)
));
Then, use it
Suppose a controller Documents. Call on a view:
<?= $this->_render('element', 'foo', $data, array('controller' => 'documents')); ?>
This will look for a file inside views/documents/_foo.html.php and if doesn't exists, fallback to /views/elements/foo.html.php
This kind of simple re-configuration of framework defaults, can be done in Lithium for a bunch of stuffs (default controllers paths to create namespaces, views paths, libraries, etc ...)
One more example to re-maps your template paths so you can have stuff like pages/users_{username}.php instead of the Lithium default:
https://gist.github.com/1854561
Fixed it. Works like a charm. Zend like Partials in Lithium.
<?php
namespace app\extensions\helper;
use lithium\template\View;
class Partial extends \lithium\template\Helper
{
public function render($name, $folder = 'elements', array $data = array())
{
$view = new View(array(
'paths' => array(
'template' => '{:library}/views/' . $folder . '/' . $name . '.{:type}.php'
)
));
return $view->render('all', $data);
}
}
Can be used in templates like:
<?php echo $this->partial->render('filename', 'foldername', compact('foo', 'bar')); ?>
There is a plugin for partials. https://github.com/dmondark/li3_partials
I am trying to use phpThumb in my application by making a custom autoloader.
class My_Loader_Autoloader_PhpThumb implements Zend_Loader_Autoloader_Interface {
static protected $php_thumb_classes = array(
'PhpThumb' => 'PhpThumb.inc.php',
'ThumbBase' => 'ThumbBase.inc.php',
'PhpThumbFactory' => 'ThumbLib.inc.php',
'GdThumb' => 'GdThumb.inc.php',
'GdReflectionLib' => 'thumb_plugins/gd_reflection.inc.php',
);
/**
* Autoload a class
*
* #param string $class
* #return mixed
* False [if unable to load $class]
* get_class($class) [if $class is successfully loaded]
*/
public function autoload($class) {
$file = APPLICATION_PATH . '/../library/PhpThumb/' . self::$php_thumb_classes[$class];
if (is_file($file)) {
require_once($file);
return $class;
}
return false;
}
}
i saved this file as PhpThumb.php in the loaders/Autoloader folder. Then added this line to the bootstrap file:
Zend_Loader_Autoloader::getInstance()->pushAutoloader(new My_Loader_Autoloader_PhpThumb());
But it produces an error saying the class was not found. I am guessing that the 'CustomLoader_PhpThumb.php' needs to be saved somewhere else. Any idea guys ?
Update1:
Bootstrap.php file contents
<?php
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
protected function _initAutoload()
{
$autoLoader=Zend_Loader_Autoloader::getInstance();
$resourceLoader=new Zend_Loader_Autoloader_Resource(array(
'basePath'=>APPLICATION_PATH,
'namespace'=>'',
'resourceTypes'=>array(
'form'=>array(
'path'=>'forms/',
'namespace'=>'Form_'
),
'models'=>array(
'path'=>'models/',
'namespace'=>'Model_'
),
)
));
//return $autoLoader;
$resourceLoader->addResourceType('loader', 'loaders/', 'My_Loader_');
$autoLoader->pushAutoloader($resourceLoader);
$autoLoader->pushAutoloader(new My_Loader_Autoloader_PhpThumb());
}
}
?>
I'm also using PhpThumb and the same autoloader. In my case however it is called My_Loader_Autoloader_PhpThumb and is located in APPLICATION_PATH . '/loaders/Autoloader/PhpThumb.php.
In my Bootstrap.php, first I load the loaders path to the Zend_Loader_Autoloader and then I push the My_Loader_Autoloader_PhpThumb autoloader as follows:
$autoLoader = Zend_Loader_Autoloader::getInstance();
$resourceLoader = new Zend_Loader_Autoloader_Resource(array(
'basePath' => APPLICATION_PATH,
'namespace' => '',
));
$resourceLoader->addResourceType('loader', 'loaders/', 'My_Loader_');
$autoLoader->pushAutoloader($resourceLoader);
$autoLoader->pushAutoloader(new My_Loader_Autoloader_PhpThumb());
Hope this will help.
PhpThumb.php should be saved to library/CustomLoader folder, and you should setup autoloader for this class also, for example in application.ini:
autoloaderNamespaces[] = "CustomLoader_"
or in Bootstrap.php:
$autoloader->registerNamespace('CustomLoader_');
I couldn't try, I hope it works!
I did it in another way, long more easy, without any autoloader, just using "My".
1.- Create a phpThumbFolder with all the files of the library into project/library/My/PhpThumb
2.- Create a file named PhpThumbFactory.php into that folder with the following content:
require_once('ThumbLib.inc.php');
class My_PhpThumb_PhpThumbFactory
{
public static function create ($filename = null, $options = array(), $isDataStream = false)
{
return PhpThumbFactory::create($filename, $options, $isDataStream);
}
}
3.- Enjoy:
public function editimageAction()
{
//rutaImg is the physical path to my images defined in application.ini
$rutaImg = Zend_Registry::get('config')->rutaImg. "test.jpg";
//Call to our "gateway" class
$thumb = My_PhpThumb_PhpThumbFactory::create($rutaImg);
//Resize
$thumb->adaptiveResize(20, 20);
//Show
$thumb->show();
$this->_helper->viewRenderer->setNoRender();
$this->_helper->layout->disableLayout();
}
I hope it can help anyone ;)
P.D. The "gateway" class is to avoid modifying any code of the library, so any possible update is easy.
Ok here is a method I use for initializing models in my controller actions:
protected $_tables = array();
protected function _getTable($table)
{
if (false === array_key_exists($table, $this->_tables)) {
include APPLICATION_PATH . '/modules/'
. $this->_request->getModuleName() . '/models/' . $table . '.php';
$this->_tables[$table] = new $table();
echo 'test ';
}
return $this->_tables[$table];
}
Then when I call the _getTable() method two times (for example once in init() method and once in the controller action) it prints:
test test test test test test
On top of the page. Shouldn't it just return the object from the _tables array() because of the array_key_exists() check? In other words shouldn't the part inside the array_key_exists() function get executed only once when the method is called multiple times?
UPDATE:
So the problem is this - for some reason the layout gets printed twice (so it's layout printed and inside the layout where there is layout()->content; ?> it prints the layout again). I have no idea why it does this as it worked well on the previous server and also on localhost.
In the snippet you show:
protected $this->_tables = array();
This is not valid syntax, it should be:
protected $_tables = array();
Also, why not just use include_once and let PHP handle this for you? Alternatively, you could use the Zend_Loader. Don't reinvent the wheel.
What you are really looking for is the loading of module based resources. Instead of re-inventing the wheel, why not just use the (module) resource autoloaders of ZF? See the documentation at:
http://framework.zend.com/manual/en/zend.loader.autoloader-resource.html
When you use Zend_Application (I'm assuming you don't), you get these automatically. If you don't you could do something like
$loaders = array();
$frontController = Zend_Controller_Front::getInstance();
foreach($frontController->getControllerDirectory() as $module => $directory) {
$resourceLoader = new Zend_Application_Module_Autoloader(array(
'namespace' => ucfirst($module) . '_',
'basePath' => dirname($directory),
));
$resourceLoader->addResourceTypes(array(
'table' => array(
'path' => 'models/',
'namespace' => 'Table'
));
$loaders[$module] = $resourceLoader;
}
//build array of loaders
$loader = Zend_Loader_Autoloader::getInstance();
$loader->setAutoloaders($loaders);
//set them in the autoloader
This approach is a bit naive, but it should give you nice autoloading.