Cache files permissions fix for Kohana Twig module - caching

How to configure Kohana + Twig module so the Twig will set "writable by all" permissions on all of it's cache directory and it's descendant files?
So, for example, when I run my application through the Apache module (mod_php) and cache file owner is apache (or httpd) user, I will be able to remove cache files (to clean the cache or completely remove whole application) using regular user and ssh access.
I'm able to do it with Kohana's cache, but Twig's cache is created somehow differently.

It's not very easy, but not too complicated either. I have achieved state presented below by trial-and-error method.
Create a class that inherits from Twig_Cache_Filesystem and will be used instead of it. Check this out:
<?php
namespace Application\Twig;
class Cache_Filesystem extends \Twig_Cache_Filesystem
{
public function write($key, $content)
{
$old = umask(0000);
parent::write($key, $content);
umask($old);
}
}
Note, that this class must have it's name unique, so it is a good idea to namespace it. Also, it must be accessible to other code, so consider using composer's autoloading feature.
This is the fix itself, rest of the guide is just the way of implementing it into Kohana+Twig ecosystem.
Copy Twig.php from modules/kohana-twig/classes/Twig.php into your application's directory, i.e. application/classes/Twig.php (thank you Kohana's Cascading Filesystem!)
Modify a bit newly copied file, to let Twig_CacheInterface instance be passed in the config file (application/config/twig.php) instead of just a simple string (specifying to the Twig's cache directory). Take a look of my example:
<?php defined('SYSPATH') or die('No direct script access.');
class Twig extends Kohana_Twig
{
/**
* Initialize the Twig module
*
* #throws Kohana_Exception
* #return bool
*/
public static function init()
{
$path = Kohana::$config->load('twig.environment.cache');
if (is_string($path)) {
return parent::init();
} else if ($path instanceof Twig_CacheInterface) {
return true;
}
throw new Kohana_Exception('Twig cache could not be initialized');
}
}
In configuration file for kohana-twig module, i.e. application/config/twig.php (if not yet copied from module to your application, do it now), define environment.cache key like this:
return array(
'loader' => array(
'extension' => 'twig',
'path' => 'views',
),
'environment' => array(
'auto_reload' => (Kohana::$environment >= Kohana::TESTING),
'autoescape' => true,
'base_template_class' => 'Twig_Template',
// Following line is related to this issue and fix:
'cache' => new \Application\Twig\Cache_Filesystem(APPPATH . 'cache/twig'),
'charset' => 'utf-8',
'optimizations' => - 1,
'strict_variables' => false,
),
'functions' => array(),
'filters' => array(),
'tests' => array(),
}
This works for me. Hopefully it will help someone struggling with similar problem.

Related

laravel livewire uploaded file create object from path and save to s3

I'm uploading a file to a file upload component, and then passing the temporary file path to the parent component with an event. In the parent component I need to save the file to s3.
I need to pass the path or a file object or something back to the parent component, and then save it, but I can't seem to get it to work.
I've tried sending over a File object, as well as an UploadedFile object, my latest iteration is to try with a File object, and I'm getting the following error:
Unresolvable dependency resolving [Parameter #0 [ <required> string $path ]] in class Symfony\Component\HttpFoundation\File\File
So in my child component I have this code:
public function updatedFile()
{
$fileObj = new File($this->file->path());
$this->emitUp('fileUploaded', $fileObj);
}
In my parent component I'm listening for the fileUploaded event, which calls the save method:
public function save(File $uploadedFile)
{
if ($path = Storage::putFileAs(env('APP_ENV') . '/statements', $uploadedFile->name, 's3')) {
$this->statement = new Statement([
'location_id' => $this->location->id,
'file_name' => $uploadedFile->name,
'path' => $path,
'uploaded_by' => Auth::user()->id,
]);
$this->statement->save();
}
}
I've also tried using $uploadedFile->storeAs() and I get the same result. It seems like the $uploadedFile object is not the right type. I don't know if I need a Storage object or what and I can't seem to find a good answer in the docs.
The path I have available after uploading the file in my livewire component is the temporary file name that livewire saves the file as in local storage. I also need the original file name as well, like what was uploaded as I'm saving that to the database.
If I remove the type hint on the save() method I get Attempt to read property "name" on array. Why is $uploadedFile an array and not an object? I guess if I remove the type hint it just gets sent over as an array. I dunno..
Here's the solution I came up with:
child component:
public function updatedFile()
{
$this->validate([
'file' => 'required|max:12288'
]);
$this->emitUp('fileUploaded', [$this->file->path(), $this->file->getClientOriginalName()]);
}
parent component:
public function save($uploadedFile)
{
if ($path = Storage::disk('s3')->put(env('APP_ENV') . '/statements/' . $uploadedFile[1], file_get_contents($uploadedFile[0]))) {
$this->statement = new Statement([
'location_id' => $this->location->id,
'file_name' => $uploadedFile[1],
'path' => $path,
'uploaded_by' => Auth::user()->id,
]);
$this->statement->save();
}
}

ZF2 - Saving a result of a function in cache

I made a view helper that checks if an external URL exists before outputting it. Some of those URLs are in my main layout, so that check is quite slowing down my site by calling all those urls all the times, to check if they exist. I would like to save the output of that function so that it only checks an URL if the same one hasn't been checked already in less than an hour, or a day. I believe I should use Zend Cache to do that? But I have no idea where to start, do you have any suggestions, easy solutions or some basic tutorial to learn? Thanks!
Add global config for cache service, like here:
config/autoload/global.php
'service_manager' => array(
'abstract_factories' => array(
'Zend\Cache\Service\StorageCacheAbstractServiceFactory',
)
),
config/autoload/cache.global.php
return array(
'caches' => array(
// Cache config
)
)
Use factory to create your View Helper:
Application/Module.php::getViewHelperConfig()
'LinkHelper' => function ($sm) {
$locator = $sm->getServiceLocator();
return new LinkHelper($locator->get('memcached'))
}
Use cache service in your View Helper:
LinkHelper.php
protected $cache;
public function __construct($cache)
{
$this->cache = $cache;
}
public function __invoke($url)
{
$cacheKey = md5($url);
if ($this->cache->hasItem($cacheKey) {
return $this->cache->getItem($cacheKey);
}
$link = ''; // Parse link
$this->cache->setItem($cacheKey, $link);
return $link;
}

Laravel4 seed specific environment

We're are developing multiple applications based on Laravel 4. These applications run on the same webserver.
The Laravel4 environment detection is based on the hostname which sucks because we have multiple applications on the same machine.
We created a work-around in the detection area so that it will set the environment based on the url.
We run the artisan --env=my_env migrate command when we update the applications DB. The problem is in the seeding, the seeding command doesn't have a env option so it will try to seed the db based on the hostname wich will not be correct.
I'm trying all day to find a solution but I can't find any on the Internet and my attempts to build a new command is just taking too much time and energy.
Does someone knows how to set the environment when seeding?
PS: I run the commands on the server through Grunt and I know the environment -inject it into the command-.
You pointed it very well, Laravel environment guessing sucks the way we use to use it, but you can change that:
This is how I do set my environment flawlessly, so I don't have to deal with hostnames and still don't get my local environment conflict with staging and production.
Create a .environment file in the root of your application and define your environment and add your sensitive information to it:
<?php
return array(
'APPLICATION_ENV' => 'development', /// this is where you will set your environment
'DB_HOST' => 'localhost',
'DB_DATABASE_NAME' => 'laraveldatabase',
'DB_DATABASE_USER' => 'laraveluser',
'DB_DATABASE_PASSWORD' => '!Bassw0rT',
);
Add it to your .gitignore file, so you don't risk having your passwords sent to Github or any other of your servers.
Right before $app->detectEnvironment, in the file bootstrap/start.php, load your .environment file to PHP environment:
foreach(require __DIR__.'/../.environment' as $key => $value)
{
putenv(sprintf('%s=%s', $key, $value));
}
And then you just have to use it:
$env = $app->detectEnvironment(function () {
return getenv('APPLICATION_ENV'); // your environment name is in that file!
});
And it will work everywhere, so you don't need to have separate dirs for development and production anymore:
<?php
return array(
'connections' => array(
'postgresql' => array(
'driver' => 'pgsql',
'host' => getenv('DB_HOST'),
'database' => getenv('DB_DATABASE_NAME'),
'username' => getenv('DB_DATABASE_USER'),
'password' => getenv('DB_DATABASE_PASSWORD'),
'charset' => 'utf8',
'prefix' => '',
'schema' => 'public',
),
),
);
Note that I don't set a fallback:
return getenv('APPLICATION_ENV') ?: 'local';
Because I want it to fail on every server I deploy my app to, to never forget configuring my environment on them.
Then you just have to select the environment in your DatabaseSeeder class:
public function run()
{
if( App::environment() === 'development' )
{
$this->call('UserTableSeeder');
}
}
I thought about the situation some days and got to the conclusion that what we're trying to do isn't the correct way.
The correct way would be that every application has his own config files -with the different envs-. This way the resolve function of Laravel works fine.
The situation now is that we have multiple clients within one application and strore does -clients- configuration files within one application. In this case the hostname resolve will return the one client's -every time the same client- config beacuse the clients applications run on the same machine.
Our solution
We are going to write a deployment script for the different clients so that every client has his own application with their configs only (copy application, copy/overwrite client config into app).
Work-around
The answer of #Antonio Carlos Ribeiro works offcourse but had to much impact on our application. We use the different environments and with this solution we had to use the same user/pass info on all environments or provide a different .environment file.
I wrote an Artisan command to make our deployment work for the moment. This command can seed a database with the configuration of the provided environment (php artisan db:seed_env my_env).
use Illuminate\Console\Command;
use Illuminate\Config\Repository;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
class SeedEnvironmentDb extends Command {
/**
* The console command name.
*
* #var string
*/
protected $name = 'db:seed_env';
/**
* The console command description.
*
* #var string
*/
protected $description = 'Seed a database with the configuration of the environment';
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* #return mixed
*/
public function fire()
{
$cmd = $this;
$app = App::make('app');
// force the environment to the given one.
$env = $app->detectEnvironment(function() use ($cmd) {
return $cmd->argument('environment');
});
// create new config with the correct environment and overwrite the current one.
$app->instance('config', $config = new Repository(
$app->getConfigLoader(), $env
));
// trigger the db seed (now with the correct environment)
$this->call('db:seed');
}
/**
* Get the console command arguments.
*
* #return array
*/
protected function getArguments()
{
return array(
array('environment', InputArgument::REQUIRED, 'The environment to seed.'),
);
}
/**
* Get the console command options.
*
* #return array
*/
protected function getOptions()
{
return array();
}
}

Codeigniter: Extend CI_Lang class when controller loaded to use &get_instance()

I want to extend my CI_Lang class to get language values from the database. So I created a copy of the CI_Lang file and rewrote the load and construct functions.
private $CI;
function __construct()
{
parent::__construct();
log_message('debug', "Language Class Initialized");
$this->CI = &get_instance();
}
I enabled hooks in the config file and created a new hook:
$hook['post_controller_constructor'] = array(
'class' => 'MY_Lang',
'function' => '__construct',
'filename' => 'MY_Lang.php',
'filepath' => 'hooks'
);
This is working correctly. However, when I try to load languages, it's still using the old functions from CI_Lang and not the extended one. Any ideas?
Ok I found the solution without using any hooks.
First: I had to place MY_Lang.php to 'core' folder.
Second: "$this->CI = &get_instance();" has to be placed in the "load" function and not in the construct.
Hope it helps, its working here. :)

Magento: How to know many blocks are cached

i cached my custom block inherit of Mage_Core_Block_Template. I cached the bloc with the next constructor:
protected function _construct()
{
$this->addData(array(
'cache_lifetime' => 120,
'cache_tags' => array(Mage_Core_Model_Store::CACHE_TAG, Mage_Cms_Model_Block::CACHE_TAG),
));
}
Right, i want verify that this block is cached. How i can list all block cached in my Magento.
I want a similar instruction:
var_dump($this->getLayout()->getUpdate()->getHandles());exit;
to see all layout , in blocks cached.
thx.
You can specify cache_key for your block:
protected function _construct()
{
$this->addData(array(
'cache_key' => 'some_static_or_dynamic_key', // can be static or dynamic
'cache_lifetime' => 120,
'cache_tags' => array(
Mage_Core_Model_Store::CACHE_TAG,
Mage_Cms_Model_Block::CACHE_TAG),
)
);
}
And then you can ensure that block is cached by calling:
Mage::app()->loadCache('your_cache_key');
Here is good article about blocks caching.
To see if Magento created your cache, you could search for the file that contains in it's name your tags in the var folder. Also make sure you have your cache activated for this to work.

Resources