Reordering Collections in Laravel - php

I am working on a Laravel project where people can post tiles on a page then click a button to move them up or down on the page. Currently I have a table setup for tiles like so:
$table->string('tile_name');
$table->text('tile_rules');
$table->integer('tile_order');
Then on the frontend I have a button should either move the tile up or down depending which arrow you press. For my up function I thought I could just take the current order from the Tile and Add which does work in its simplest form, but my question is what is the best approach for looping back through and updating all the other tiles on the page? I think it is also fair to say there will never likely be more than ten tiles on a page that would need reordering.
I was thinking this must be do able with a foreach loop:
$currentOrder = $currentTile->tile_order;
foreach($Tiles as $tile) {
Tiles::whereKey($tile->id)->update(['tile_order' => ++$order]);
}
but what I missing is how do I tell it to start at a particular tile and only update the tiles above or below it depending on whether or not I am moving it up or moving it down?
If someone could push me in the right direction that would be greatly appreciated!

I debated handling on the frontend and allowing the user to save the order when they had completed it, but instead I created an Up and Down function that would find the item above or below it and just switch the order integer with it. This seems to work better than looping through everything and updating the count.
if ($tileAbove == 0) {
session()->flash('message', 'This Tile can not be moved any higher');
} else {
//Update the current Tile to the new order and tileAbove to the old order
$tileAboveObj = $positionTiles->filter(function($item) use ($tileAbove) {
return $item->tile_order == $tileAbove;
})->first();
Tiles::whereKey($currentTile->id)->update(['tile_order' => $tileAbove]);
Tiles::whereKey($tileAboveObj->id)->update(['tile_order' => $currentTileOrder]);
}
with $tileAbove just being the current tile order subtracted by 1.

Related

Send data from div to controller in laravel

Is that possible instead of using <input name="...."/> I get my value from div or span etc. ?
currently I get my data directly from database, base on product id, but as my product might have discount that will show different price with what is saved in my database and I cannot show it as input so i need to pass it through div or span etc.
code:
here is my code now:
public function addingItem(Request $request, $id)
{
$product = Product::findOrFail($id);
Cart::add(array(
'id' => $product->id,
'name' => $product->title,
'price' => $product->price, // this comes directly from products table
));
}
with my code i always will get 45.325 but I need to get 35.325 during discount time.
That's why i need to pass it through div and cannot use input here.
any idea?
As far as your PHP code is concerned, data doesn't come from any particular part of a page, it comes from the HTTP request sent by the browser. An HTML form is just the simplest way to get the browser to add some data to that request. This may seem like nitpicking, but it has important consequences.
First, it means that what you are asking for is absolutely possible. You just need to write some JavaScript to run in the browser and tell the browser to add that value to the request. A simple way would be to have a hidden input field on the form and set the value in the JavaScript, but you can also create a completely custom request and send it to the server (AJAX).
Second, though, it means that any user can submit any data to your application by telling their browser to submit their choice of value not yours. Consequently, you have to be very careful of what data you trust, and trusting the browser to send you a price sounds like a really bad idea. What's to stop someone giving themselves a 100% discount by editing the value on the page?
Somewhere, you know what discounts you're offering. That discount is a core part of your application, so however the view knows what discount to show, the rest of the application should be able to know the same way. This probably means moving some code out of your view into a new function, which can be used by various parts of the application; that makes each use more readable, and means you don't have to change it in lots of places if the requirements get more complex.
SOLVED
well I decided to bring my codes to controller instead of using ajax or other ways, here is how I've done it:
$discounts = Discount::all();
$mytime = Carbon::now();
//get discounted price or normal price of product
$price = $product->discounts;
if($price->count() > 0 ) {
foreach($discounts as $disc){
if($disc->value_to >= $mytime) {
$price = $product->price - $disc->amount;
}
}
}else{
$price = $product->price;
}
Hope it help others.

Laravel get static array of random numbers and use it in pagination

I am developing an application in Laravel 5.5 ... it is kind of a testing system...
What I want to achieve is that when user clicks on RUN TEST, it will generate random set of questions (let's say 5) then I want them to be served to the user one by one ... I did a pagination in AJAX so the questions can be served by pages .. and after that user will click on SUBMIT which will submit the form ..
I am able to get the random list of questions
In the TestController within the method "exec_test" is
// get random id
$q_id = Question::select('id')
->where('test_id','=',$test_id)
//->where('id','=',114)
->orderByRaw("RAND()")
->take(3)
->get();
This will get 3 random ID's for that specific test ...
Following code in the same method is
// get data
$data = array (
'tests' => Test::select('id','code','name',DB::raw('duration_m * 60 as duration_m'),'questions','passing_score')
->where('id','=',$test_id)
->orderBy('code', 'asc')
->paginate($this->page_limit),
'test_questions' => Question::select('questions.id','questions.question_header','questions.question_detail_local_url')
->join('tests','tests.id','=','questions.test_id')
->where('test_id','=',$test_id)
->whereIn('questions.id',$q_id)
//->orderByRaw("RAND()")
//->take(4)
->paginate($this->test_question_page_limit),
'test_answers' => Answer::select('id','answer_text_cleaned')
->whereIn('question_id',$q_id)
->get()
);
// check for ajax requests
if ($request->ajax()) {
return view('/custom/test/run_test_quests', $data)->render();
}
return view('/custom/test/run_test_info',$data);
But I don't know how can I make that first query static and to make it served one by one (per page) to the user .. so he can go trough all questions
Do you have any suggestions please?
while paginating the first page would be 1, it would be specified in the url too.
try this:
if($request->input('page') ==1)
{
//code for first page
}else{
//code for random
}
this is just a suggestion. Sorry if I understood the question wrong

Laravel 5: To cache or use sessions for building a site-wide banner?

I'm building a feature into a Laravel 5 app that will allow you to set the content of a status banner that will display across the top of the page. We will be using this banner both to display page-specific things (status messages, etc) and site-wide announcements (every user sees the same thing, banner stays the same for awhile).
Right now, I've implemented this by using Laravel sessions to allow banners to be added by calling a helper method from any controller or middleware:
// Call set_banner from in a controller or middleware (for persistent banners)
function set_banner($banner_text, $banner_class, $banner_persistant=false, $replace=false)
{
$banners = session()->get('banners', []);
// Create new banner
$banner = [
'text' => $banner_text,
'type' => $banner_class,
'persistent' => $banner_persistant
];
// Only put banner in array if it's not already there
if( !in_array($banner, $banners) ) {
// Either override existing banners, or add to queue
if( !$replace ) session()->push('banners', $banner);
else session()->put('banners', [$banner]);
}
}
// Called by default in the master.blade.php template
function get_banners()
{
$banners = session()->pull('banners', Array());
foreach( $banners as $banner ) {
// Print out each banner
print '<div class="col-md-12"><div class="text-center alert alert-block alert-'.$banner['type'].'">';
print $banner['text'];
print '</div></div>';
// Push back into the session if banner is marked as persistent
if ( $banner['persistent'] ) session()->push( 'banners', $banner );
}
}
Banners are created in controllers or middleware like this:
set_banner("<b>Note:</b> This is a sample persistant-scope banner set in a controller", "success", true);
Is there a better way to accomplish storing both page-level and site-wide banners? My concerns is that hitting the session on every pageload may be inefficient, especially for banners that won't be changing for long periods of time. Will this approach mess with Laravel's cache, etc?
As you said the banners do not change that often. Hence for me i would implement it using Cache. This improves performance since we need only one use to have the banners cached. And for the rest its retrieved faster from the Cache rather Session.
Do you want to have to change code to change the banner of a given page?
I would suggest instead creating a "pages" package, where each page route name is entered into a database.
From there, from your page service provider you get Page::getModel()->banner_text or something similar.
The method would look for a db result matching the current route name with a result within db.
when a controller method is triggered you simply call
Page::getBannerText()
That method will pull the current route name, pull the page result related to that page if it exists or create it if it does not exist (easy way to get everything). You cache the db query result for X hours, days or whatever so whenever someone else makes a call, you don't even need to deal with any storage on client side.
This allows you to modify the value from a db fascet. Its the more "proper" way to do it.

PHP: Check for profile fields completedness

I have a social networking site built on a PHP framework. I'm using a plugin to award members points when they update their profile. Right now, whenever a member clicks on 'Save' it triggers the profileupdate event, and that event triggers the points being awarded. But, even if the profile fields are all empty, the event is still triggered and they still get points… so, my clever users are gaming the system to get points without really updating their profile :\
I want to add a function that checks that the profile fields aren't empty -- or, ideally, checks that a significant amount of changes have been made to at least 1 of the profile fields, but I'm not sure how to do that.
I'm still pretty new to PHP (about 1 year experience), so if anyone could help both with explaining what the checking process should be and the specifics on the code to execute the checking function, I'd really appreciate it!
Here are the current events and functions:
When the owner of the page clicks on 'Save', this is the event in the core of the PHP framework that gets triggered to notify the user of the update:
$owner->save();
trigger_event('profileupdate', $owner->type, $owner);
system_message(echo("profile:saved"));
This is the function in the points plugin that checks to see if the plugin is configured to award points based on a profile update, and then calls the points_add function to add points to the user:
function points_profile($event, $type, $object) {
if ($points = get_plugin_setting('profileupdate')) {
if (function_exists('points_add')) {
points_add(get_logged_in_user_guid(), $points, $event, $type, $object->entity_guid);
}
}
return(true);
}
This is an example of how the individual profile fields are defined/labelled -- ie, "admin_defined_profile_1"
if (save_config("admin_defined_profile_$id", $label) &&
save_config("admin_defined_profile_type_$id", $type) &&
save_config('profile_custom_fields', $fieldlist))
look on rowcount() http://www.php.net/manual/en/pdostatement.rowcount.php
it will -on single UPDATE -return 1 if anything was actually changed and 0 if nothing was changed.

Creating configurable product programmatically

I'm trying to create configurable products programmatically in Magento 1.5.1.
I understand I need first to create simple related products, what I did. Now I manage to associate these simple products to make a configurable one.
Here is the critical part...
I keep the ids and some of the attributes values in an array, so I can later make my configurable product, but some of them are missing, I don't know which method to call.
I found this entry in Magento Wiki, that helped me and seems to fit my needs.
However, at the end the author is setting two things :
$product->setConfigurableProductsData($data);
$product->setConfigurableAttributesData($data);
and the values in the arrays have been taken in the admin page source using Firebug....and then translated into PHP arrays (array example for the first call) :
"I’ve harcoded the values for my associated products and attribute
data. You can get attribute data by viewing the source through the
admin interface and using Firebug for Firefox."
$data = array('5791'=>array('0'=>array('attribute_id'=>'491', // I already got this
'label'=>'vhs', // this too
'value_index'=>'5', // but what is value_index ?
'is_percent'=>0,
'pricing_value'=>'')),
'5792'=>array('0'=>array('attribute_id'=>'491',
'label'=>'dvd',
'value_index'=>'6',
'is_percent'=>0,
'pricing_value'=>'')));
My question is : is there a way to retrieve these values without using Firebug (which in my script won't help me a lot !), but programmatically. I already found a way to retrieve attribute values, labels, etc... using its code, but one field I don't know is value_index.
I guess this may be the option position in an option list, but not sure.
Also if someone knows a good/better way to create a configurable product in Magento, please tell me.
Any help is welcome thank you.
It seems you're asking where to retrieve the value_index value where you already have the label. Here's what I had: I didn't test this on 1.5x.
function get_attribute_id($option, $type) {
$attributeId = Mage::getResourceModel('eav/entity_attribute')->getIdByCode('catalog_product', $type);
$attribute = Mage::getModel('catalog/resource_eav_attribute')->load($attributeId);
$attributeOptions = $attribute->getSource()->getAllOptions();
foreach ($attributeOptions as $opts_arr) {
if (strtoupper($opts_arr['label']) == strtoupper($option)) {
return $opts_arr['value'];
}
}
return FALSE;
}
$value_index = get_attribute_id('vhs', 'media_format');
No one else seemed to mention the easiest way to figure out what the value_index of vhs is: In the backend, under
Catalog > Manage > media_format > Manage Label/Options
Inspect the source of the individual form inputs. Where you have 'vhs' you should have an input named option[value][6]
As far as I understand your question, there are two options: a) create simple products by script, put the generated id's in an array and create the configurables using the ids or b) read the id's from the admin and put them in your script. Since programming is about automation I'd definately go for option a.

Categories