Symfony2 Best practices - sorting of entities - model-view-controller

I am creating an application in Symfony2. This is the first time I develop using a framework and one of my first projects. It is a student project.
In this project, I want my collections of entities to be sorted somewhere before reaching the view. This can be done in this way:
In getters on the entities on the many-to-one relations, with comparator methods on the many-side that is used by the usort() method in the getter on the one-side. Below I have a method that also fills in gaps in a collection of "Day" entities (in a form of diary), but the point is that it sorts the days with usort.
In User entity class:
public function getDaysWithNulls()
{
$days = $this->getDays()->toArray();
//get the first day and find out how many days have passed
usort($days, array("\Pan100\MoodLogBundle\Entity\Day", "daySorter"));
$firstEntry = $days[0];
$interval = $firstEntry->getDate()->diff(new \DateTime());
$numberOfDaysBack = $interval->d;
//create an array consisting of the number of days back
$daysToShow = array();
for ($i=0; $i < $numberOfDaysBack ; $i++) {
$date = new \DateTime();
$date->sub(new \DateInterval('P' . $i . 'D'));
$daysToShow[] = $date;
}
$daysToReturn = array();
foreach ($daysToShow as $day) {
//figure out if this day has an entity, if not set an empty Day object
$dayEntityToProcess = new \Pan100\MoodLogBundle\Entity\Day();
$dayEntityToProcess->setDate($day);
foreach ($days as $dayEntity) {
//check if there is a day entity
if($day->format('Y-m-d') == $dayEntity->getDate()->format('Y-m-d')) {
$dayEntityToProcess = $dayEntity;
}
}
$daysToReturn[] = $dayEntityToProcess;
}
//return a collection
return new \Doctrine\Common\Collections\ArrayCollection($daysToReturn);
}
usort uses this in the Day entity class:
static function daySorter($dayEntity1, $dayEntity2) {
$interval = $dayEntity1->getDate()->diff($dayEntity2->getDate());
if($interval->invert == 1) {
return +1;
}
else if ($interval->invert == 0) {
return 0;
}
else return -1;
}
My question is: is this the best practice for sorting and returning sorted collections, or should sorting happen somewhere else?

I did think this was a tedoius way of doing it. So I searched the web a bit, and read some more, and found that I can create custom repositories.
I will do it this way instead:
http://symfony.com/doc/2.1/book/doctrine.html#custom-repository-classes
EDIT: found out the sorting is better done in annotations:
/**
* #ORM\OneToMany(targetEntity="Day", mappedBy="user_id")
* #ORM\OrderBy({"date" = "DESC"})
**/
protected $days;

Related

Refactoring multiple same queries with different value

Is there a better way to refactor this code? It's basically the same line with different values. I thought of doing a for loop but maybe there's another way.
$date = $request->date;
$underConsideration = Application::whereDate('created_at',$date)->where('status','Under consideration')->count();
$phoneScreened = Application::whereDate('created_at',$date)->where('status','Phone screened')->count();
$interviewed = Application::whereDate('created_at',$date)->where('status','Interviewed')->count();
$offerExtended = Application::whereDate('created_at',$date)->where('status','Offer extended')->count();
You should create a separate method for this.
public function myMethod()
{
$under_consideration = $this->fetchApplicationData($request, 'Under consideration');
$phone_screened = $this->fetchApplicationData($request, 'Phone screened');
$interviewed = $this->fetchApplicationData($request, 'Interviewed');
$offer_extended = $this->fetchApplicationData($request, 'Offer extended');
}
private function fetchApplicationData($request, $status)
{
return Application::
whereDate('created_at', $request->date)
->where('status', $status)
->count();
}
That is a much cleaner code.
However, I advise that you should put the items:
Under consideration, Phone screened, Interviewed, Offer extended
into a separate table on the database and just save the status_id on your main table.
One of the major advantage on this is the speed. For example, your client wants to know all record that has a status of Interviewed for a certain date span. Database searching against integer is a lot faster than string.
You could create a method to handle the select operations. Something like:
public function yourExisitingMethod() {
$date = $request->date;
$underConsideration = getData($date,'Under consideration');
$phoneScreened = getData($date,'Phone screened');
$interviewed = getData($date,'Interviewed');
$offerExtended = getData($date,'Offer extended');
}
public function getData($date, $status) {
$data = Application::whereDate('created_at',$date)->where('status',$status)->count();
return $data;
}
This would at the very least improve the maintainability of your code, and in my opinion improves reusability and readability.

How to call information from one model to another Codeigniter

I'm stuck on this from a while.Can't figured it out.I reed documantion, tried with several videos and tried like 10 different ways, nothing is working yet.So I have one view/model for one thing, in this example Destination and I have separate files for Offers.The controllers for both are in one file.I want tho the information that is in destination to go to Offers as well.Please help I can't figure out what I'm missing:
So here is the most important parts:
destination_model.php
<?php class Destination_model extends CI_Model
{
public function getDestinationDetails($slug) {
$this->db->select('
id,
title,
information
');
$this->db->where('slug', $slug);
$query = $this->db->get('destinations')->row();
if(count($query) > 0)
{
return $query;
}
else
{
// redirect(base_url());
}
}
public function getOffersByDestination($destination_id)
{
$this->db->select('
o.short_title,
o.price,
o.currency,
o.information,
o.long_title_slug,
oi.image,
c.slug as parent_category
');
$this->db->from('offers o');
$this->db->join('offers_images oi', 'oi.offer_id = o.id', 'left');
$this->db->join('categories c', 'c.id = o.category');
$this->db->group_by('o.id');
$this->db->where('o.destination', $destination_id);
$this->db->where('o.active', '1');
return $this->db->get();
} }
And then in the controller for offers I put this:
$this->load->model('frontend/destination_model');
$this->params['destination'] = $this->destination_model->getOffersByDestination($data->id);
All I need is the title and the information about the destination.
Here is the whole controller for the offers:
$data = $this->slugs_model->getOfferDetails(strtok($this->uri->segment(2), "."));
$this->load->model('frontend/offers_model');
$this->load->model('frontend/destination_model');
$this->params['main'] = 'frontend/pages/offer_details';
$this->params['title'] = $data->long_title;
$this->params['breadcumb'] = $this->slugs_model->getSlugName($this->uri->segment(1));
$this->params['data'] = $data;
$this->params['images'] = $this->slugs_model->getOfferImages($data->id);
$this->params['similar'] = $this->slugs_model->getSimilarOffers($data->category, $data->id);
$this->params['destination'] = $this->destination_model->getOffersByDestination($data->id);
$this->params['offers'] = $this->offers_model->getImportantOffers($data->offers, $data->category, $data->id);
You need to generate query results after you get it from model,
e.g: row_array(), this function returns a single result row.
here's the doc: Generating Query Results
try this:
$this->load->model('frontend/destination_model');
$data['destination'] = $this->destination_model->getOffersByDestination($data->id)->row_array();
$this->load->view('view_name', $data);
And in your view echo $destination['attribut_name'];,
or you can print the array, to see if it's work print_r($destination);

Save multiple inputs Laravel 5.6

I'm trying to save a data to my database coming from 2 inputs which has multiple values. The scenario is that after a product has been saved, data will be save to my another table with columns 'product_id','price','size'. How ever when I tried to run my code, only the first value is saved in the column 'size', the data in 'price' are fine.
<input name="fix_size[]">
<input name="fix_price[]">
foreach($request->fix_price as $prc){
$cprice = new ContainerPrice;
$cprice->product_id = $id;
$cprice->price = $prc;
foreach($request->fix_size as $size){
$cprice->size = $size;
}
$cprice->save();
}
Remember, fix_size and fix_price are arrays.
You have to get the respective pairs of each fix_size and fix_price. So you have to monitor the index in the loop.
This is one of the possible solution in your problem:
$fix_sizes = $request->fix_size;
foreach($request->fix_price as $i => $prc){
$cprice = new ContainerPrice;
$cprice->product_id = $id;
$cprice->price = $prc;
$cprice->size = $fix_sizes[$i];
$cprice->save();
}
I may suggest to you to master the basic principles of programming and learn to debug codes by yourself.
Try this
foreach($request->fix_price as $prc){
foreach($request->fixed_size as $size){
$cprice = new ContainerPrice;
$cprice->product_id = $id;
$cprice->price = $prc;
$cprice->size = $size;
$cprice->save();
}
}
You could try this:
foreach($request->fix_price as $key => $prc) {
$cprice = new ContainerPrice;
$cprice->product_id = $id;
$cprice->price = $prc;
$cprice->size = $request->input('size')[$key];
$cprice->save();
}
The problem you had is because you loop over all elements inside the main loop and keeping only the last element. In other words, in the foreach loop, you are constantly overriding the $cprice->size property with the last you find.
Now with this code you access the "size" which has the same index as your "price".

Many-To-Many Entity Framework Update

I have an object that has a many-to-many relationship with another object. I am trying to write an update statement that doesn't result in having to delete all records from the many-to-many table first.
My data is:
StoredProcedure - StoredProcedureId, Name
Parameter - ParameterId, Name
StoredProcedure_Parameter - StoredProcedureId, ParameterId, Order
I have a UI for updating a stored procedured object (adding/removing parameters or changing the order of the parameters).
When I save, I end up at:
var storedProcedure = context.Sprocs.FirstOrDefault(s => s.SprocID == sproc.StoredProcedureId);
if (storedProcedure == null)
{
//do something like throw an exception
} else
{
storedProcedure.Name = sproc.Name;
//resolve Parameters many to many here
//remove all Params that are not in sproc.Params
//Add any params that are in sproc.Params but not in storedProcedure.Params
//Update the Order number for any that are in both
}
I know I could simply call .Clear() on the table and then reinsert all of the values with their current state (ensuring that all parameters that were removed by the UI are gone, new ones are added, and updated Orders are changed). However, I feel like there must be a better way to do this. Do many-to-many updates with EF usually get resolved by deleting all of the elements and reinserting them?
Here there is my code that I use and it works. The difference is that instead o having your 3 tables( StoredProcedure, StoredProcedure_Parameter and Parameter ) I have the following 3 tables: Order, OrdersItem(this ensure the many-to-many relation) and Item. This is the procedure that I used for updating or add an order, or after I change an existing OrderItem or add a new one to the Order.
public void AddUpdateOrder(Order order)
{
using (var db = new vitalEntities())
{
if (order.OrderId == 0)
{
db.Entry(order).State = EntityState.Added;
}
else
{
foreach (var orderItem in order.OrdersItems)
{
if (orderItem.OrderItemsId == 0)
{
orderItem.Item = null;
if (order.OrderId != 0)
orderItem.OrderId = order.OrderId;
db.Entry(orderItem).State = EntityState.Added;
}
else
{
orderItem.Order = null;
orderItem.Item = null;
db.OrdersItems.Attach(orderItem);
db.Entry(orderItem).State = EntityState.Modified;
}
}
db.Orders.Attach(order);
db.Entry(order).State = EntityState.Modified;
}
SaveChanges(db);
}
}

TYPO3 Extbase: How to render the pagetree from my model?

I want to create some kind of sitemap in extbase/fluid (based on the pagetree). I have loaded the pages table into a model:
config.tx_extbase.persistence.classes.Tx_MyExt_Domain_Model_Page.mapping.tableName = pages
I have created a controller and repository, but get stuck on the part wich can load the subpages as relation into my model.
For example:
$page = $this->pageRepository->findByPid($rootPid);
Returns my rootpage. But how can I extend my model that I can use $page->getSubpages() or $page->getNestedPages()?
Do I have to create some kind of query inside my model? Or do I have to resolve this with existing functions (like the object storage) and how?
I tried a lot of things but can simply figure out how this should work.
you have to overwrite your findByPid repository-method and add
public function findByPid($pid) {
$querySettings = $this->objectManager->create('Tx_Extbase_Persistence_Typo3QuerySettings');
$querySettings->setRespectStoragePage(FALSE);
$this->setDefaultQuerySettings($querySettings);
$query = $this->createQuery();
$query->matching($query->equals('pid', $pid));
$pages = $query->execute();
return $pages;
}
to get all pages. Than you can write your own getSubpages-method like
function getSubpages($currentPid) {
$subpages = $this->pagesRepository->findByPid($currentPid);
if (count($subpages) > 0) {
$i = 0;
foreach($subpages as $subpage) {
$subpageUid = $subpage->getUid();
$subpageArray[$i]['page'] = $subpage;
$subpageArray[$i]['subpages'] = $this->getSubpages($subpageUid);
$i++;
}
} else {
$subpageArray = Array();
}
return $subpageArray;
}
i didn't test this method, but it looks like this to get alle subpages.
i wonder that i couldĀ“t find a typo3 method that return the complete Page-Tree :( So i write a little function (you can use in an extbase extension), for sure not the best or fastes way, but easy to extend or customize ;)
first you need an instance of the PageRepository
$this->t3pageRepository = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Frontend\\Page\\PageRepository');
this->t3pageRepository->init();
make the init, to set some basic confs, like "WHERE deletet = 0 AND hidden = 0..."
then with this function you get an array with the page data and subpages in. I implement yust up to three levels:
function getPageTree($pid,$deep=2){
$fields = '*';
$sortField = 'sorting';
$pages = $this->t3pageRepository->getMenu($pid,$fields,$sortField);
if($deep>=1){
foreach($pages as &$page) {
$subPages1 = $this->t3pageRepository->getMenu($page['uid'],$fields,$sortField);
if(count($subPages1)>0){
if($deep>=2){
foreach($subPages1 as &$subPage1){
$subPages2 = $this->t3pageRepository->getMenu($subPage1['uid'],$fields,$sortField);
if(count($subPages2>0)){
$subPage1['subpages'] = $subPages2;
}
}
}
$page['subpages'] = $subPages1;
}
}
}
return $pages;
}

Resources