My index method does not advance through the result set when it's pulled from the cache; without caching, it works as expected. The page number in
the query params is correctly incremented.
I've reviewed several very old SO questions about this, but they are very out of date with the current CakePHP release (3.8).
case ('F'): // Full, paid members
$query = $this->Members->find('currentFullMembers');
$cacheKey = md5($this->request->getParam('controller') .
$this->request->getParam('action') . $report) . 'FM';
$query->cache($cacheKey);
$this->set('baseYear', $baseYear);
$this->set('reportTitle', 'Full Members');
break;
Is there something else I need to do for pagination?
Related
I'm trying to get data from an Eloquent query (that works), then order the data, then paginate the data.
I had the code ordering by date, then paginating, but now I want to order by facebook API obtained data (I get the data correctly).
The thing is I don't know what I should do first (paginate or ordering):
If I paginate first, I don't know how to order the data since the object is LengthAwarePaginator and doesn't have any orderBy method.
If I order first, I get a collection object and can't use ->paginate($perPage) to do the pagination.
This is the code:
$posts = Post::with('User')->
where('created_at', '<', new \DateTime)->
paginate($perPage);
$counter = 0;
foreach ($posts as $post) {
$url = 'http://myweb.com/' . $post['id'];
$fb_stuff = json_decode(file_get_contents('https://api.facebook.com/method/links.getStats?urls=' . $url . '&format=json'), true);
$posts[$counter]['share_count'] = $fb_stuff[0]['share_count'];
$counter++;
}
If you need to sort by some value that is not stored in the database then the only option is to fetch all records from the database, fetch the sorting data from external source (Facebook API), sort it by user defined function (see http://php.net/manual/en/function.usort.php) and then paginate.
Once you have your data sorted you can easily get the paginated version by creating a Paginator object:
$paginator = new \Illuminate\Pagination\Paginator($posts, $perPage, $currentPage);
Anyway, this solution will be quite heavy as you'll need to fetch data from Facebook API every time you want a sorted list of posts. I doubt you need real time data so I suggest to store share_count in your posts table and refresh it on regular basis, e.g. by running a scheduled laravel command.
I have this chunk of code:
//to-do
public function searchVehicles($terms, $offset=1, $order='ASC')
{
if (trim($terms) == '') {
return array();
}
$query = $this->_getQuery($terms);
$query->setStoreId(1);
if ($query->getId()) {
$query->setPopularity($query->getPopularity()+1);
}
else {
$query->setPopularity(1);
}
$query->prepare();
$query->save();
$collection = Mage::getResourceModel('catalog/product_collection');
$collection->getSelect()->joinInner(
array('search_result' => $collection->getTable('catalogsearch/result')),
$collection->getConnection()->quoteInto(
'search_result.product_id=e.entity_id AND search_result.query_id=?',
$query->getId()
),
array('relevance' => 'relevance')
);
$collection->setStore(1);
//Mage::getSingleton('catalog/product_status')->addVisibleFilterToCollection($collection);
//Mage::getSingleton('catalog/product_visibility')->addVisibleInSearchFilterToCollection($collection);
return $this->_listProductCollection($collection, $offset, $order);
}
Which is inside a Resource class and reachable via SOAP.
Before we start: Yes, I remember to do the cache flushing and recompiling process - I clarify because this is an usual issue to newbies like me xDDD.
Now: I can access such method but it returns [].
SPECIAL NOTE: $this->_listProductCollection($collection, $offset, $order); WORKS since i'm using the same method in other collections fetched from other methods in the same resource, and have no trouble at all.
Let me review the intention of my code since I'm a newbie at Magento (I'm using version 1.6.2).
The code is based on the CatalogSearch/ResultController controller's indexAction() method, and tried to learn about it.
An empty query will yield an empty result and will not bother the Magento search engine.
There's only a Store (id = 1) in the site and the search query is created like this:
private function _getQuery($terms)
{
$query = Mage::getModel('catalogsearch/query')->loadByQuery($terms);
if (!$query->getId()) {
$query->setQueryText($terms);
}
return $query;
}
The query increases it's popularity (I took this code from the controller. I assume this is for statistical purposes only).
The query is prepared (I think this means: the MySQL internal query is prepared) so I can fetch it later.
The query is saved - AFAIK this means that the query results are iterated and cached so a subsequent same query will only fetch the stored results instead of processing the search again.
At this point the query will have an ID.
I get the whole Product collection, and join it with the search result table. SEEMS that the results table has - at least (queryId, matchedProductId). I only keep the products having IDs in the matched results, and from store 1.
I list the products.
Note that the filters are currently commented.
However, the returned list is [] (an empty list) when I hit this API entry point, althought searching in the usual search bar gives me the expected result.
Question: What am I missing? What did I misunderstood in the process?
I have a Post model and I am inserting the Tags for the posts like the one below. When I am editing there can be some tags being removed. So what is the right way to remove the tags and re-insert ?
$post->setTitle($data['title']);
$post->setBody($data['body']);
$post->setSlug($data['slug']);
$tags = explode(',', $data['tags']);
// Want to remove the tags
foreach ($tags as $tag) {
$tagobj = TagQuery::create()->findOneByName($tag);
if (! $tagobj) {
$tagobj = new Tag();
$tagobj->setName($tag);
$tagobj->save();
}
$post->addTag($tagobj);
}
$post->save();
Does propel can insert in a single query or is this a worst approach .
I have asked the question in propel group, but :-( https://groups.google.com/d/msg/propel-users/x6PH_DwLtVE/H84o1cu4W4kJ
The full source code is here
The goal is to re-save the tags, when one tag is removed or one tag is added. What to do ? .
1st priority.
Optimization is second priority.
Update2 :
I modified the code as something like below with the reply I got
$tags = explode(',', $data['tags']);
foreach ($tags as $tag) {
$tagobj = TagQuery::create()->findOneByName($tag);
if (! $tagobj) {
$tagobj = new Tag();
$tagobj->setName($tag);
$tagobj->save();
}
}
// var_dump($tags);
$tagcollection = TagQuery::create()->findByName($tags);
// var_dump($tagcollection);
// exit;
$post->setTags($tagcollection);
Now I am getting array to string conversion error .
Notice: Array to string conversion in /var/www/harisample/vendor/propel/propel/src/Propel/Runtime/Connection/StatementWrapper.php on
line 171 Call Stack: 0.0001 131940
{main}() /var/www/harisample/web/index.php:0 0.0243 1259056
Aura\Framework\Bootstrap\Web->exec() /var/www/harisample/web/index.php:13 0.0243 1259108
Aura\Framework\Web\Controller\Front->exec() /var/www/harisample/package/Aura.Framework/src/Aura/Framework/Bootstrap/Web.php:71 0.0243 1259436
Aura\Framework\Web\Controller\Front->request() /var/www/harisample/package/Aura.Framework/src/Aura/Framework/Web/Controller/Front.php:168 0.0314 1694584
Aura\Web\Controller\AbstractPage->exec() /var/www/harisample/package/Aura.Framework/src/Aura/Framework/Web/Controller/Front.php:222 0.0316 1699500
Aura\Web\Controller\AbstractPage->action() /var/www/harisample/package/Aura.Web/src/Aura/Web/Controller/AbstractPage.php:168 0.0316 1699576
Aura\Web\Controller\AbstractPage->invokeMethod() /var/www/harisample/package/Aura.Web/src/Aura/Web/Controller/AbstractPage.php:206 0.0316 1699960
ReflectionMethod->invokeArgs() /var/www/harisample/package/Aura.Web/src/Aura/Web/Controller/AbstractPage.php:231 0.0316 1699976
Hari\Sample\Web\Post\Page->actionEdit() /var/www/harisample/package/Aura.Web/src/Aura/Web/Controller/AbstractPage.php:231 0.0856 5802116 1
Hari\Sample\Model\Base\Post->save() /var/www/harisample/package/Hari.Sample/src/Hari/Sample/Web/Post/Page.php:127 0.0874 5808356 1
Hari\Sample\Model\Base\Post->doSave() /var/www/harisample/package/Hari.Sample/src/Hari/Sample/Model/Base/Post.php:930 0.0881 5813420 1
Hari\Sample\Model\Base\PostTagQuery->delete() /var/www/harisample/package/Hari.Sample/src/Hari/Sample/Model/Base/Post.php:1000 0.0881 5813700 1
Propel\Runtime\ActiveQuery\ModelCriteria->delete() /var/www/harisample/package/Hari.Sample/src/Hari/Sample/Model/Base/PostTagQuery.php:557 0.0881 5814628 1
Propel\Runtime\ActiveQuery\Criteria->doDelete() /var/www/harisample/vendor/propel/propel/src/Propel/Runtime/ActiveQuery/ModelCriteria.php:1324 0.0883 5817716 1
Propel\Runtime\Connection\StatementWrapper->execute() /var/www/harisample/vendor/propel/propel/src/Propel/Runtime/ActiveQuery/Criteria.php:2408 0.0883 5817772 1
PDOStatement->execute() /var/www/harisample/vendor/propel/propel/src/Propel/Runtime/Connection/StatementWrapper.php:171
Thanks
I guess your goal is optimizing the number of (mysql ?) request, isn't it ?
I think this is not possible, mainly because Propel object saving rely on other steps - think of preSave(), postSave(), behaviors also - needing a single saving query execution for every object.
By trying to make an optimized query, you would loose the benefit of the Propel saving workflow and relations management.
On the other hand, I am not sure about the way clearTags() really works, I think it just remove object references but does not delete records in the database.
You must have in your BasePost.php file a setTags() method that will actually replace any previous relation with the new object collection you provide.
I'm making sth similar, but still something is not good. Maybe you can try, maybe it will work on your project.
$tagNames = $tags->getTags();
$tagsArray = explode(',', $tagNames);
$postTagToDelete = PostTagQuery::create()->filterByPostId($post->getId())->find();
if ($postTagToDelete) {
$postTagToDelete->delete();
}
foreach ($tagsArray as $tagName) {
$tag = TagQuery::create()->filterByName($tagName)->findOne();
//when i find an existing tag,
// there is no need to create another one
//I just simply add it **(it's not working here)**
if ($tag != null) {
$post->addTag($tag);
} else {
//when tag is new
$tag = new Tag();
$tag->setName($tagName);
$post->addTag($tag);
}
}
$post->save()
See my problem here.
To be more specific, let's pretend that I have four elements in $tagsArray.
[first, second, third, fourth]
Every of them IS the database already, so it gonna enter first if four times.
The problem is that only second, third and fourth will be saved. There will be no first . Why?
Another example is that if I have array[first] and do the same (first is in the databse already) it will be saved every only the second time. So I have sth like is in database, database empty, is in database, database empty,[...] every request attempt.
I have two models: Plans and PlanDetails.
Relationship is: PlanDetails hasMany Plans. Plans belongTo PlanDetails.
In the PlanDetails view.ctp, I am pulling in related Plans.
I am trying to sort the Plans by ANY field (I've tried them all), and I cannot get it working. I assume I am overlooking something very simple.
Here is my base code:
PlanDetail >> view.ctp:
...foreach ($planDetail['Plan'] as $plan_edit) :
$class = null;
if ($i++ % 2 == 0) {
$class = ' class="altrow"';
}...
<?php echo $this->Paginator->sort('Plan ID', 'Plan.id'); ?>...
...<?php echo $plan_edit['id']; ?>
plan_details_controller.php:
...function view($id = null) {
if (!$id) {
$this->Session->setFlash(__('Invalid plan detail', true));
$this->redirect(array('action' => 'index'));
}
$this->PlanDetail->recursive = 2; // To run the editable form deeper.
$this->set('planDetail', $this->PlanDetail->read(null, $id));
$this->set('plan', $this->paginate('Plan'));
}...
I should add, no errors are being thrown and the sort() arrows on the ID field are showing as expected, but the sort order DOES not change when clicked either way.
Sorry, I'm not able to comment on the question itself, but I've noticed that in your action, you set planDetail to be the PlanDetail record you read (with recursive set to 2), and then you set plan to be the result of the paginate call.
Then, in your view template, you're iterating over $planDetail's contained Plan association, like this:
foreach ($planDetail['Plan'] as $plan_edit):
But in order to get the sorting and pagination done, you need to be displaying the results of the paginate call i.e. iterate over the records contained in $plan.
Do a debug($plan) in your view template to see what results you get there and to see if the records' ordering changes when you sort by different fields.
Also, perhaps you're using syntax I'm not aware of, but if you simply call $this->paginate('Plan') in your controller, I don't know that you're going to get only the related Plan records for your particular PlanDetail record. (There's nothing tying the $id passed into your view action with the Plan records.) You might need to add some conditions to the paginate call, like so:
$this->paginate['Plan'] = array('conditions' => array('Plan.plan_detail_id' => $id));
$this->set('plans', $this->paginate('Plan'));
Here is what I did to solve this. Based on some helpful direction from johnp & tokes.
plan_details/view.ctp:
...$i = 0;
foreach ($plan as $plan_edit) : // note $plan here.
}...
In my plan_details_controller.php view action:
$conditions = array("Plan.plan_detail_id" => "$id");
$this->set('plan', $this->paginate('Plan', $conditions)); // note "plan" in the first argument of set (this is required to pass the results back to the view). Also. The $condition is set to return ONLY plans that match the plan_detail_id of id (on the plan_details table).
And in my view, in order to get my results (because I changed the array name), I had to change the way I was getting the values to:
$plan_edit['Plan']['modified'] // note I placed ['Plan'] in front of these calls as the array called for this to get the data...
Well until the next problem! SOLVED.
In my Symfony/Doctrine app, I have a query that orders by RANDOM(). I call this same method several times, but it looks like the query's result is being cached.
Here's my relevant code:
$query = $table->createQuery('p')
->select('p.*, RANDOM() as rnd')
->orderBy('rnd')
->limit(1)
->useQueryCache(null)
->useResultCache(null);
$result = $query->fetchOne();
Unfortunately, the same record is returned every time, regardless of me passing null to both useQueryCache and useResultCache. I tried using false instead of null, but that didn't work either. Lastly, I also tried calling both setResultCacheLifeSpan(0) and setResultCacheLifeSpan(-1), but neither call made a difference.
Any insight on how to prevent caching since I want a different random row to be selected each time I call this method?
Edit: I also tried calling clearResultCache(), but that just ended up causing an error stating: "Result Cache driver not initialized".
Edit 2: As requested, here's the SQL generated by calling $query->getSqlQuery():
SELECT c.id AS c__id, c.name AS c__name, c.image_url AS c__image_url,
c.level AS c__level, c.created_at AS c__created_at, c.updated_at
AS c__updated_at, RANDOM() AS c__0 FROM cards c ORDER BY c__0 LIMIT 1
It turns out I'm a moron. I tried to simplify my query for this question, and in doing so, I didn't capture the true cause. I had a where() and andWhere() call, and the combination of conditions resulted in only one possible record being matched. Thanks for taking the time to respond, everyone, sorry to have wasted your time!
Doctrine also caches entities you created in the same request/script run.
For instance:
$order = new Order();
$order->save();
sleep(10); // Edit this record in de DB in another procces.
$q = new Doctrine_Query();
$result = $q->select()
->from('Order o')
->where('o.id = '.$order->id);
$order = $result->getFirst();
print_r($order->toArray());
The print_r will not contain the changes you made during the sleep.
The following code will remove that kind of memory cache:
$manager = Doctrine_Manager::getInstance();
$connection = $manager->getCurrentConnection();
$tables = $connection->getTables();
foreach ( $tables as $table ) {
$table->clear();
}
PS: Added this answer because I found this topic trying to resolve above issue.