Make Doctrine use result cache by default - caching

I'm binding Memcache to Doctrine and it seems I have to useResultCache explicitly in every query. Is it possible to make it true by default, with the ability to useResultCache(false) where it's not needed?

Create a wrapper class/function that explicitly sets useResultCache(true) and use that everywhere instead of the native function.

I know this question is old, but I'll write up the best answer that comes into my mind.
1) Abstract away your dependency to interface ( i.e. - use dependency injection pattern to inject EntityManager into your class that creates queries and use EntityManagerInterface instead )
Now, either:
a) [ Better, but longer ] Create a new composition-related implementation for EntityManagerInterface, that will proxy calls to original entityManager and will set result cache flag to true:
<?php
class CachedEntityManager implements EntityManagerInterface {
private $proxiedManager;
public function __construct(EntityManagerInterface $proxiedManager) {
$this->proxiedManager = $proxiedManager;
}
public function createQuery($dql = '') {
$query = $this->proxiedManager->createQuery($dql);
$query->useResultCache(true);
}
[... proxy all the calls forth to proxiedManager ...]
}
b) [ Not as good, but shorter ] Extend the EntityManager class and override the createQuery. Remember that this in general is not a good practice and you should definitely not write anything in that class anymore but instead refactor into a) :
<?php
class CachedEntityManager extends EntityManager {
public function createQuery($dql = '') {
$query = parent::createQuery($dql);
$query->useResultCache(true);
}
}

You can hack the Doctrine core a little by setting the default value of $_useResultCache to TRUE in \Doctrine\ORM\AbstractQuery. This will make all queries use the resultCacheDriver by default, and you can easily turn the cache off for individual queries using $query->useResultCache(FALSE)
It's a useful little hack that saves you a lot of typing, but be careful; I've found that the caching driver won't cache lazy-loaded associations that haven't been initialized (which is obvious now I think about it). Sometimes it's safer to just turn result caching on for each individual query.

Related

How to toggle laravel trashed filter off temporarily?

Say I've got an A, which has a B that has a C that has a D. I want to go from A to D, but any one (or all) of the objects might have been deleted. So I have to do this:
$d = $a->b()->withTrashed()->first()->c()->withTrashed()->first()->d()->withTrashed()->first()
Which is horrible. I would really rather do this:
turnOffTrashedFilter();
$d = $a->b->c->d;
Does laravel have such an ability?
Note that this is just an example - the situation that prompted this question is actually a lot more complicated, with various calls nested in other calls such that it's not practically possible to use withTrashed as above. I need to turn off the filter for the duration of the request, without having to modify huge swathes of code to incorporate two parallel paths.
No built-in, but it can be done
There is no built in way to disable the automatic soft delete filtering. However, it is possible. The soft delete filter is a global scope, added to the boot method of the class. It can be removed like so:
\Event::listen('eloquent.booted:*', function($name) {
$name = substr($name, 17); // event name is "eloquent.booted: some/class"
$class = new \ReflectionClass($name);
$prop = $class->getProperty('globalScopes');
$prop->setAccessible(true);
$scopes = $prop->getValue();
foreach ($scopes as $c => &$s) {
unset($s['Illuminate\Database\Eloquent\SoftDeletingScope']);
}
$prop->setValue($scopes);
});
This hooks into the booted event, which is fired immediately after the global scope gets added to the class. It then opens the (private static) attribute globalScopes, which is a list of the attached global scopes, and removes the soft deleting one. This will prevent the softdelete scope from being attached to any models, provided their static boot method is called after the event listener is added.
Instead of this you can use withTrashed() in your relations:
public function aTrashed()
{
return $this->hasOne(A::class)->withTrashed();
}
public function bTrashed()
{
return $this->hasMany(B::class)->withTrashed();
}
public function cTrashed()
{
return $this->belongsToMany(C:class)->withTrashed();
}
// Then use it
$d = $z->aTrashed->bTrashed->cTrashed;

Laravel Facade Implementation

I am confused as to how to use the cache in Laravel. I can either use the Cache facade and do something like …
use Cache;
public function someMethod()
{
Cache::remember('users', 60 , function() {
return DB::table('users')->get();
});
}
Or I could use something like this …
use Illuminate\Contracts\Cache\Repository;
protected $cache;
public function __construct(Repository $repository)
{
$this->cache = $repository;
}
public function someMethod()
{
$this->cache->remember('users', 60 , function() {
return DB::table('users')->get();
});
}
Both will implement the same method remember from vendor/laravel/framework/src/Illuminate/Cache/Repository.php
Repository class which implements vendor/laravel/framework/src/Illuminate/Contracts/Cache/Repository.php which I have included in the second method.
As per Laravel docs:
The Illuminate\Contracts\Cache\Factory and Illuminate\Contracts\Cache\Repository contracts provide access to Laravel's cache services. The Factory contract provides access to all cache drivers defined for your application. The Repository contract is typically an implementation of the default cache driver for your application as specified by your cache configuration file.
However, you may also use the Cache facade, which is what we will use throughout this documentation. The Cache facade provides convenient, terse access to the underlying implementations of the Laravel cache contracts.
So can I conclude that both the approach are same. The Cache Facade provides me a cleaner implementation, that's it.
You would get the same result in your application. It's the same but not the same.
In your second approach you are using dependency injection. Which makes it easier to write tests for your class. This way you get a better maintainable application.
Have a deeper look at dependency injection. Here is a nice article: Dependency Injection with Laravel’s IoC.

Alternative to using codeigniter libraries for additional classes

I have an existing controller (classA) which needs to use a new helper class (classB). Typically I would place classB into a library and do
$this->load->library('classb');
$this->classb->method();
However, I've run into a problem where I am defining const's in my classB which are required by the constructor
classB {
const MYDEFINE = 1;
...
}
The problem with this approach is the definition of MYDEFINE is NOT available until I load the library, but I need to create the $params array with the arguments to send the classB constructor. So I get a case of chicken vs. egg
$params = array();
$params['open_mode'] = classB::MYDEFINE;
$instance = $this->load->library('classB', $params);
I've been able to solve this problem by not using a library - and instead using a #include_once('classB') in my classA controller which is working fine. The file classB.php is therefore stored in the controllers directory.
I'm wondering if others have run across this problem and how they might have solved it (other than by decaaring the consts elsewhere). I looked at a post by PhilSurgeon (http://philsturgeon.co.uk/blog/2010/02/CodeIgniter-Base-Classes-Keeping-it-DRY) on an alternative method but its not quite the right fit for this problem (at least I don't think so).
I'm unclear why you would declare a constant, and then load it into the config when you initialize the class...that makes no sense, is why you have the chicken-and-egg issue
I would set things up roughly as:
private $myvar = 'My Constant Value';
function __construct() ... etc
and then you can access it using:
$this->myvar
anywhere in your library class, including the construct if you want to change it via your config
EDIT: You could still use a constant is that is more appropriate, but then pass it to the $this->myvar in your construct() as a above. The point is, your Constant should never be worked with outside of the class
how about creating a bootstrap library
like
include 'path/to/class/b';
class Init_class_b Extends class_b
{
function __construct($params)
{
// handle the variables here
parent::__construct();
}
}
then:
$this->load->library('Init_class_b',$params_for_construct);
$this->Init_class_b->method()

Something that escapes me about Symfony's controllers

Take a look to that code
<?php
namespace Sestante\SestanteBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Sestante\SestanteBundle\Model\StrutturaManager;
class MainController extends Controller
{
public function indexAction(Request $request)
{
return $this->render('SestanteSestanteBundle:Main:index.html.twig');
}
public function showLodgingsAction(Request $request)
{
$repo = $this->getDoctrine()->getRepository('SestanteSestanteBundle:Struttura');
$usr = $this->get('security.context')->getToken()->getUser();
$usrId = $usr->getId();
$sm = new StrutturaManager($repo);
$lodgingList = $sm->retrieveLodgingsFromUser($usrId);
return $this->render('SestanteSestanteBundle:Main:showLodgings.html.twig',array('lodgingList' => $lodgingList));
}
}
This is a controller for an application that I've been writing.
Take a look to showLodgingsAction. I've tryied to place all business logic into a model (StrutturaManager) that with a repository (that I've passed directly from controller because, as far I know, they're available only here or via D.I.) query my db, do some elaboration and return a list that I'll render onto a template.
First question: Is this "code separation" good, or exists a better way for do what I'm trying to do?
Second question: suppose that, now, I want to use an object of StrutturaManager type into indexAction. Remember that mine object want a repository. So, have I to declare again, and again, and again, all my object for every controller's action where I want to use them? I suppose that must exist a smarter method but, at the moment, I don't understand which.
Define StrutturaManager as a service and inject the EntityManager into it. This way the manager will have access to repositories you need and controllers won't know about Doctrine nor repositories — which is a good practice.

Codeigniter models loaded in controller overwritten by models loaded in models

I'm having Codeigniter object scope confusion.
Say I load a model in a controller:
$this->load->model('A');
$this->A->loadUser(123); // loads user with ID 123
// output of $this->A now shows user 123
$this->load->model('B');
$this->B->examineUser ();
// output of $this->A now shows user 345
class B extends Model
{
public function examineUser ()
{
$this->load->model('A');
$this->A->loadUser(345); // loads user with ID 345
}
}
I would have thought that $this->A would be different from $this->B->A but they are not. What is the best solution to this issue? It appears the ->load->model('A') in the examineUser () method does nothing because it was loaded in the controller. Then the call to loadUser () inside that method overwrites the stored properties of $this->A. This seems like a bugfest waiting to happen. If I needed global models, I would have use static classes. What I wanted was something scoped pretty much locally to the model object I was in.
Is there a way I can accomplish this but not go way outside of CI's normal way of operating?
Followup/related:
Where do most people put there "->load->model" calls? All at the beginning of a controller action? I figured it would be easier -- though perhaps not excellent programming from a dependency injection perspective -- to load them in the model itself (construct or each method).
Whenever you use the Loader Class ($this->load->), it will load the object into the main CI object. The CI object is the one you keep referring to as $this->. What you've done is load model A twice into the CI object.
Essentially, all object loaded using the Loader class goes into a single global scope. If you need two of the same type, give them different names, as per $this->load->model('A','C'). I don't know of any way around it unless you revert to using bog-standard PHP.
In my team's code, we generally load the models in the controller's constructor, then load the data to send to the view in the function, often _remap().
This is not how the loader works sadly. CodeIgniter implements a singleton pattern, which will check to see if the class is included, instantiated and set to $this->A then will be ignored if loaded again. Even if you are inside a model, $this->A will be referenced to the super-instance via the __get() in class Model. Alis it, or just do:
class B extends Model
{
public function examineUser ()
{
$user = new A;
$user->loadUser(345); // loads user with ID 345
}
}
Here's what I've decided to do, please comment if you have advice:
I've extended the CI Loader class:
<?php
class SSR_Loader extends CI_Loader
{
function __construct()
{
parent::__construct ();
}
/**
* Model Retriever
*
* Written by handerson#executiveboard.com to create and return a model instead of putting it into global $this
*
* Based on original 2.0.2 CI_Loader::model ()
*
*/
function get_model($model)
{
if (empty ($model))
{
return;
}
$name = basename ($model);
if (!in_array($name, $this->_ci_models, TRUE))
{
$this->model ($model);
}
$name = ucfirst($name);
return new $name ();
}
}
Do any CI guru's see a problem with that before I invest time in changing my code a bit to accept the return obj, ala:
// in a controller:
public function test ($user_id=null)
{
$this->_logged_in_user = $this->load->get_model ('/db/users');
$this->_viewed_user = $this->load->get_model ('/db/users');
$this->_logged_in_user->load($this->session->userdata ('user.id'));
$this->_viewed_user->load($user_id);
}
I could also do private $_logged_in_user to make it available in the controller but positively force it to be limited to just the current controller and not spill anywhere else, or I could just do $_logged_in_user = $this->load->get_model ('/db/users'); and limit it to just the current method, which is probably what I'll do more often.
This seems like a pretty straightforward way to "fix" this issue (I say "fix" b/c it's not really a bug, just a way of doing things that I think is a bad idea). Anyone see any flaws?

Resources