Deleting one of a collection on parent update - php

I am trying to delete (or create) a models associated objects when it is updated. Each bar has several taps. When you create a bar, these tap objects are created, and you can update that number and additional taps will be created or deleted as necessary.
Originally I just wanted to use pop like this:
$taps=$bar->taps;
if ( $taps_old < $taps_new){
for ($i = $taps_old; $i < $taps_new; $i++) {
$tap = Growlertap::create(['growlerstation_id' => $id]);
}
}
elseif ($taps_old > $taps_new) {
for ($i = $taps_new; $i < $taps_old; $i++) {
$taps->pop();
}
which doesn't work but doesn't give me an error. I know the if statement is working fine because the code below works:
elseif ($taps_old > $taps_new) {
for ($i = $taps_new; $i < $taps_old; $i++) {
Beertap::where('bar_id', '=', $id)->first()->delete();
}
}
This seems to not be the simplest way to write this. Is there a better way to write this?
By the way, for those wondering, this is in my update function in my controller.

pop() will remove the last item in your local collection, but it won't persist that change to the database.
Assuming it's a Beertap object, something like this should work:
Warning: untested code
...
elseif ($taps_old > $taps_new) {
for ($i = $taps_new; $i < $taps_old; $i++) {
$delete_me = $taps->pop();
$delete_me->delete();
}
}
or more succinctly: $taps->pop()->delete();

This should work Unfortunately this doesn't work because the DELETE statement doesn't support offsets.
Beertap::where('bar_id')->skip($taps_new)->delete();
So it skips as many taps as you want to keep and deletes the rest. You might want to use orderBy if it matters which rows get deleted.
Update
This should totally work now. First get all id's to delete from the collection and then delete them with one query
$idsToDelete = $taps->slice($taps_new)->modelKeys();
Beertap::destroy($idsToDelete);
Update 2
You can optimize the creation process as well (so that it's done in a single query)
$data = [];
for ($i = $taps_old; $i < $taps_new; $i++) {
$data[] = ['growlerstation_id' => $id];
}
Beertap::insert($data);
Note that you will loose the Eloquent features like automatic timestamps and model events when choosing to use insert().

Related

I want to delete data in xml but it can't

When I try to delete, I can't delete it properly. It will stuck at number 2
if(isset($_GET['action'])) {
$mahasiswaa = simplexml_load_file('input.xml');
$nim = $_GET['nim'];
$index = 0;
$i =1;
$i++;
foreach($mahasiswaa->mahasiswa as $mahasiswa){
if($mahasiswa['nim']==$nim){
$index = $i;
break;
}
}
unset($mahasiswaa->mahasiswa[$index]);
file_put_contents('input.xml', $mahasiswaa->asXML());
}
your $i variable is constantly 2, the i++ should probably be inside the loop?
also, if your condition is never met, $index is 0 and its use will likely lead to an error.
The code will act only on the first match, whats ok, if that is what you expect.

DBAL inside of for loop doesn't work properly

I created a function inside a longer plug-in for shopware, which is supposed to create a random number for every row in the database that has a "NULL" value in the "vouchercode" column. Right now I replaced the for-loop condition with a fixed number, because I wanted to make sure the problem doesn't occur because of the for-loop condition.
The problem is, that the for-loop just has effect on the database once.
For instance: I have this table 's_plugin_tnev'. Inside of that table are 6 rows. 4 of these have "NULL" as value inside of the vouchercode column.
So as far as I understand my code. It should loop 5 times through the same table and every time update one of those "NULL"-value columns, meanwhile after every loop one of those "NULL"-value columns should be filled with a random number and therefore no longer be SELECTed nor UPDATEd by this for-loop.
Though as mentioned earlier this doesn't happen. The for loop just works once apparently.
Here is my code snippet:
public function generateCode()
{
//Repeat action 5 times
for($i = 0; $i <= 4; $i++)
{
$rand = 0;
//Creates 16 times a number and add it to the var
for ($i = 0; $i<15; $i++)
{
$rand .= mt_rand(0,9);
}
//On Checkoutcomplete add $rand to database table
$addInt = "UPDATE s_plugin_tnev SET vouchercode = $rand
WHERE vouchercode IS NULL
LIMIT 1";
$connect = Shopware()->Db()->query($addInt);
}
}
As you can see I use the DBAL Framework, because this is the best supported way by Shopware.
My idea would be that the mistake has something to do with the $connect variable or that DBAL is not communicating fast enough with the Database.
Maybe someone has more experience with DBAL and could help me out.
Thanks in advance,
Max K
You have two for loops with $i, so on your first iteration, at the end the $i value is 15 and the first loop is executed only once.
Try this instead :
public function generateCode()
{
//Repeat action 5 times
for($i = 0; $i <= 4; $i++)
{
$rand = 0;
//Creates 16 times a number and add it to the var
for ($j = 0; $j<15; $j++) // $j NOT $i <---
{
$rand .= mt_rand(0,9);
}
//On Checkoutcomplete add $rand to database table
$addInt = "UPDATE s_plugin_tnev SET vouchercode = $rand
WHERE vouchercode IS NULL
LIMIT 1";
$connect = Shopware()->Db()->query($addInt);
}
}

Sorting Steam Web Api GetPlayerSummaries response

I'm making class which will get data about teams - 5 Steam users basing on 32bit SteamIDs stored in database for each team. It's translated then to 64bit SteamID.
I need response in correct order, because there is specified captain of the team.
And here's the problem - GetPlayerSummaries always returns profiles in random order. I want these to be sorted like in url.
I've tried already sort() methods, but it seems not working, like I want to.
I've tried matching 'steamid' with this translated 64 bit SteamID like this:
$profile_get = json_decode(file_get_contents('http://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/?key=mywebapikey&steamids='.$stmid64['capt'].','.$stmid64['p2'].','.$stmid64['p3'].','.$stmid64['p4'].','.$stmid64['p5']),true);
$profile_get = $profile_get['response'];
foreach($profile_get['players'] as $profile){
if($profile['steamid'] === $stmid64['capt']){
$profile_got = array(
0 => $profile
);
}
elseif($profile['steamid'] === $stmid64['p2']){
$profile_got[1] = $profile;
}
elseif($profile['steamid'] === $stmid64['p3']){
$profile_got[2] = $profile;
}
elseif($profile['steamid'] === $stmid64['p4']){
$profile_got[3] = $profile;
}
elseif($profile['steamid'] === $stmid64['p5']){
$profile_got[4] = $profile;
}
}
where $stmid64 is 64bit SteamID, but it obviously don't work :(
var_dump($profile_got[0]);
var_dump($profile_got[1]);
var_dump($profile_got[2]);
var_dump($profile_got[3]);
var_dump($profile_got[4]);
and var_dump($profile_got); returns NULL.
I've tried many different codes, but they didn't work also.
I hope you can help me with not doing all requests separately.
$profile_get = json_decode(file_get_contents('http://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/?key='.$mywebapikey.'&steamids='.$stmid64['capt'].','.$stmid64['p2'].','.$stmid64['p3'].','.$stmid64['p4'].','.$stmid64['p5']),true);
for ($i = 0; $i < 5; $i++) {
if ($i == 0)
$player = 'capt';
else
$player = 'p'.($i+1);
for ($j = 0; $j < 5; $j++) {
if ($stmid64[$player] == $profile_get['response']['players'][$j]['steamid']) {
$profile_got[$i] = $profile_get['response']['players'][$j];
break;
}
}
}
var_dump($profile_got[0]);
var_dump($profile_got[1]);
var_dump($profile_got[2]);
var_dump($profile_got[3]);
var_dump($profile_got[4]);
cheers
this will work as intended, it will order your array by 'capt' (why not p1 instead ? , you could save 3 lines), 'p2', 'p3', 'p4', 'p5'. you can still extend this in many ways but basically this is how to put them in the right order. also mind that i stored your (well mine) api key inside a $var

Sentry 2 permissions array

I have an admin panel which enables admins to assign different permissions to a user. The way that I do this is through tick boxes and when ticked it should assign a 1 to that permission.
The only problem is, the permissions are dynamic and so needs to go through a loop. I've had some trouble trying to grasp how I would got about assigning permissions this way as in my guess needs to loop through an array and then place the values into another array.
Does anyone know how I would go about this?
I have tried things like...
$park = Input::get('parks');
$permissions = array();
for($i = 0; $i < count($park); $i++)
{
$permissions = $park[$i] => 1;
}
Or...
$park = Input::get('parks');
for($i = 0; $i < count($park); $i++)
{
$park[$i] => 1;
}
Obviously the first one comes up with errors, but the second one will just come out as [1,1,1,1] .
Any help would be appreciated.

Problem looping through usernames

I am trying to loop through an array of usernames and for each username, execute a mysql_query on each.
<?php
for ($i = 0; $i < count($u); $i++)
{
$j = $i + 1;
$s = $database->checkUserPlayedRecent($u);
if (mysql_num_rows($s) > 0)
{
?>
<tr>
<?php
echo "<td>$j</td>";
?>
<?php
echo "<td>$u[$i]</td>";
?>
<?php
echo "<td>$p[$i]</td>";
?>
</tr>
<?
}
}
?>
As you can see, $u is each username.
I want each username to only appear in the echo statements if each one has num_rows > 0.
At the moment nothing is displaying.
But there should be results being returned!
Can someone help please.
The sql:
$q = "SELECT id FROM ".TBL_CONF_RESULTS." WHERE (home_user = '$u' OR away_user = '$u') AND date_submitted >= DATE_SUB(CURDATE(),INTERVAL 14 DAY)";
This line :
for ($i = 0; $i < count($u); $i++)
indicates that $u is an array -- and not a single name.
And $i is used to keep track of the current index in that array.
So, in your loop, you should be working with $u[$i] -- which will be the "current" line of the array :
$s = $database->checkUserPlayedRecent($u[$i]);
Note that you could probably rewrite your loop, using a foreach loop, like this :
foreach ($u as $currentPlayer) {
$s = $database->checkUserPlayedRecent($currentPlayer);
// ...
}
With foreach, no need to keep track of the current index -- makes code easier to write and understand, in my opinion ;-)
You should get in the habit of keeping count() outside of your conditional. You're count()ing the same array every time which is a waste of cycles.
$total = count($u);
for ($i=o; $i < $total; $i++) ...
I would definitely query these users all at once, especially since your query is abusing mysql_num_rows when you should be using the following sql:
select username, count(username) from user where username IN (your,array,of,usernames) group by username;
then your foreach loop would iterate over the results and you could reference each row without having to call yet another mysql_* method.
I'd be tempted to rewrite the query to accept the array of names and use an IN statement, so that you could execute the whole of your database activity in a single query rather than once for every entry in the array. It would almost certainly be faster.
If you show us the query that you're using in your checkUserPlayedRecent() method, we may be able to help with this.

Categories