How can I retrieve the latest question of each thread in Propel 1.6? - propel

I want to get the newest entries for each of my threads (private messaging system) with Propel 1.6 making use of the fluid ModelQuery interface. This would allow me to reuse both methods for getting newest entries and only getting entries where a user is involved (nobody wants to see messages not for him).
I already found out that in standard-SQL I have to use a subquery to get the newest entry for each of my forum threads. I also found out that in Propel you have to use a Criteria::CUSTOM query to achieve this, but the whole Criteria::CUSTOM stuff seems to be pre-Propel-1.6, because none of the examples makes use of the new ModelQuery.
Now the problem is, that I want to make use of the concenation feature in ModelQueries, where you can attach several own methods to each other like this:
$entries = MessageQuery::create()
->messagesInvolvingUser($user) // user retrieved or sent the message
->newestFromThread() // get the latest entry from a lot of Re:-stuff
I do not think that this would still be possible if I had to use
$c = new Criteria();
$c->add([the subquery filter]);
in newestFromThread().
What’s the best method to retrieve the latest entry for each thread given the following scheme (thread_id means that all messages belong to the same correspondence, I want only one entry per thread_id):
id(INT)
title(VARCHAR)
thread_id(INTEGER)
date(DATETIME)
The current PHP-implementation looks like this:
<?php
class MessageQuery extends BaseMessageQuery {
public function messagesInvolvingUser($user) {
return $this
->where('Message.AuthorId = ?', $user->getId())
->_or()
->where('Message.RecipientId = ?', $user->getId());
}
public function newestFromThread() {
return $this;
// To be implemented
}
}
And I am using it like this:
$messages = MessageQuery::create()
->messagesInvolvingUser(Zend_Auth::getInstance()->getIdentity())
->newestFromThread()
->find();

How about ordering results by date (DESC) and to limit to one result ?

Considering the answers in a similar question about pure SQL solutions, I guess it is easiest to add a new column newest indicating which message in a communcation is the newest. This probably fits the object-oriented approach of Propel better, too. I could write my application like this then:
public function preInsert(PropelPDO $con = null) {
$this->setNewest(1);
$this->getEarlier()->setNewest(0);
return true;
}

Related

Get availability of formers for a sitting

I have two forms; the first is the form formers with two fields (name, firstname).
I also have the form trainings with two fields (date_sitting, fk_former).
My problem, if I want to add the other sitting today (07/07/2019), I would like to see only the formers who have no training today.
Here, I retrieve a former who has a sitting today.
Do you think it's possible to get only the formers who have no of sitting for now?
Edit: 10/07/2019
Controller Training
public function index()
{
$trainings = Training::oldest()->paginate(5);
$formersNoTrainingToday = Training::whereDate('date_sitting', "!=", Carbon::today())
->orWhere('date_sitting', null)->get();
return view('admin.trainings.index', compact('trainings', 'formersNoTrainingToday'))
->with('i', (request()->input('page',1) -1)*5);
}
And
public function create()
{
$formers = Former::all();
return view('admin.trainings.create', compact('formers','trainings'));
}
I would like to see only the formers who have no training today.
Sure - you can determine your correct list of candidates to show by using the following query:
$formersNoTrainingToday = Training::whereDate('date_sitting', "!=", Carbon::today())
->orWhere('date_sitting', null)->get();
This should work... but it assumes a few things within your code / db. If this fails, consider a few options to replace the whereDate section above:
Using where:
->where('date_sitting', '!=', \Carbon::today()->toDateString())
Using formatted date if that column on the DB is a different format than Carbon:
->whereDate('date_sitting', "!=", Carbon::now()->format('m/d/Y'))
If you're not using Carbon for some reason, you can try the raw query route for today:
->whereDate('date_sitting', "!=", DB::raw('CURDATE()'))
Bottom line, here are a number of ways to get close to this. But you may need to tweak this on your own to suit your needs. You may need to take Timezone or some hours of difference into account, so you may need to add a range or buffer. But the above should get you close if not all the way there.
HTH

Sorting by case using Hibernate

We have a typeahead that allows our customers to do a global search of their clients. Based on a 'filterText', we want to retrieve all the clients where any of the following fields contain the filterText: clientName, clientStreet, clientCity... but now there's a requirement and we want to prioritize the results where the clientName contains the filterText. (They should be shown first)
We currently create a customerSpecification, and the Predicate that it's being used is the following one:
return criteriaBuilder.or(
criteriaBuilder.like(customerName, likeFilter),
criteriaBuilder.like(customerStreet, likeFilter),
criteriaBuilder.like(customerCity, likeFilter),
criteriaBuilder.like(customerState, likeFilter),
criteriaBuilder.like(customerZip, likeFilter),
criteriaBuilder.like(customerCountry, likeFilter),
tempPred
);
and then we use it to get the Page with all the results
customerRepository.findAll(customerSpecification, pageable);
How can we introduce this new requirement? Any approaches?
Some pages suggest to use selectCase, doing something like this:
Expression<Object> caseExpression = criteriaBuilder.selectCase()
.when(criteriaBuilder.like(root.get(CustomerEntity_.name), likeFilter), 1)
.otherwise(2);
Order order = criteriaBuilder.desc(caseExpression);
criteriaQuery.orderBy(order);
But I can't find the way to make it works. I also found some talks about PageRequest, which receives a Sort parameter, but I didn't find how it would help, as this object is too simple for what we're looking for.
Thanks

Laravel - Eloquent multiple delete vs destroy array

I was wondering what's the best way to destroy multiples database entries with ELOQUENT and I don't find a way to determine that.
So I have 3 array of id's (2 with ints, 1 with strings).
Is it better to go with a foreach and ->delete() every entry or destroy the array ?
When I look at the destroy function, it states the following :
We will actually pull the models from the database table and call
delete on each of them individually so that their events get fired
properly with a correct set of attributes in case the developers
wants to check these.
And the code clearly shows :
$key = $instance->getKeyName();
foreach ($instance->whereIn($key, $ids)->get() as $model) {
if ($model->delete()) {
$count++;
}
}
So I guess there's no real difference and the destroy function is just to avoid the use of a foreach. Can anyone confirm or inform and explain ?
Thanks :)
At first you need to know the difference between destroy and delete, destroy is think to be used for removing an entity (object/model) and delete for being used on a query builder.
Both are different ways but they have the same purpose you can do like:
Model::destroy(array(1, 2, 3));
or
$ids = explode(",", [1,2,3]);
$model->find($ids)->each(function ($model, $key) {
//Do things before deleting
$model->delete();
});
But as you can see the first one is just more direct, on the second one you can do custom things before deleting.

Is it possible to eager load arbitrary queries in Eloquent?

I'm working in Laravel 4, and I have a Child model with multiple EducationProfiles:
class Child extends EloquentVersioned
{
public function educationProfiles()
{
return $this->hasMany('EducationProfile');
}
}
If I wanted to get all the EducationProfiles for each kid under age 10 it would be easy:
Child::where('date_of_birth','>','2004-03-27')->with('educationProfiles')->all();
But say (as I do) that I would like to use with() to grab a calculated value for the Education Profiles of each of those kids, something like:
SELECT `education_profiles`.`child_id`, GROUP_CONCAT(`education_profiles`.`district`) as `district_list`
In theory with() only works with relationships, so do I have any options for associating the district_list fields to my Child models?
EDIT: Actually, I was wondering whether with('educationProfiles') generates SQL equivalent to:
EducationProfile::whereIn('id',array(1,2,3,4))
or whether it's actually equivalent to
DB::table('education_profiles')->whereIn('id',array(1,2,3,4))
The reason I ask is that in the former I'm getting models, if it's the latter I'm getting unmodeled data, and thus I can probably mess it up as much as I want. I assume with() generates an additional set models, though. Anybody care to correct or confirm?
Ok, I think I've cracked this nut. No, it is NOT possible to eager load arbitrary queries. However, the tools have been provided by the Fluent query builder to make it relatively easy to replicate eager loading manually.
First, we leverage the original query:
$query = Child::where('date_of_birth','>','2004-03-27')->with('educationProfiles');
$children = $query->get();
$eagerIds = $query->lists('id');
Next, use the $eagerIds to filterDB::table('education_profile') in the same way that with('educationProfiles') would filter EducationProfile::...
$query2 = DB::table('education_profile')->whereIn('child_id',$eagerIds)->select('child_id', 'GROUP_CONCAT(`education_profiles`.`district`) as `district_list`')->groupBy('child_id');
$educationProfiles = $query2->lists('district_list','child_id');
Now we can iterate through $children and just look up the $educationProfiles[$children->id] values for each entry.
Ok, yes, it's an obvious construction, but I haven't seen it laid out explicitly anywhere before as a means of eager loading arbitrary calculations.
You can add a where clause to your hasMany() call like this:
public function educationProfilesUnderTen() {
$ten_years_ago = (new DateTime('10 years ago'))->format('Y-m-d');
return $this->hasMany('EducationProfile')->where('date_of_birth', '>', $ten_years_ago)
}

How To Use Magento Collections to Run Query, Get Results, and Print Them

I am fairly new to programming, php, Magento, and most of all, SQL. Please forgive me if this is somehow a dumb question.
I am trying to use Magento collections to select two different columns in two different tables and join them. These two columns contain product numbers that follow the same conventions and my goal is to get and display the product numbers that field a (lets call it 'product_id') contains that field b ('item_nr') does not.
Here is my function so far, located currently in a model that will be called by a controller action.
public function importCompare() {
$orderlistCollect = Mage::getModel('personal_orderlist/orderlist')->getCollection()
->addFieldToSelect('product_id')
->addFieldToFilter('b.item_nr', null)
->getSelect()
->joinLeft( array('b'=>$this->getTable('catalog/product')), 'main_table.product_id = b.item_nr', array('b.item_nr'));
echo $orderlistCollect;
}
By echoing the variable, I get the following query.
SELECT `main_table`.`product_id`, `b`.`erp_item_nr`
FROM `mag1personal_orderlist` AS `main_table`
LEFT JOIN `` AS `b` ON main_table.product_id = b.item_nr
WHERE (b.item_nr = '')
This looks fairly close to what I want, however the big problem is that I have no idea how to retrieve the information I should derive from this query and echo it. I've tried to use a variety of collection manipulation methods to no avail. Is it easy to use them out of order as well?
Any help here is appreciated.
Collections use interfaces from PHP's standard library to implement for each-able behaviors.
If that sounded like greek, give this a try.
foreach($orderlistCollect as $item)
{
$data = $item->getData();
var_dump($data);
$sku = $item->getSku();
var_dump($sku);
$sku = $item->getData('sku');
var_dump($sku);
}
If you're interested in learning how to do with with your own PHP objects, the Object Iteration section of the manual is a good place to start. However, there's no need to dive deep on this — just treat a collection like you would an array of objects, and you'll be fine.

Resources