DynamoDB PHP getItem() - How to tell if item does not exist - php

I am writing a "Get or Create" method that attempts to get an item, but if it doesn't exist, it will create a fresh new version of it. Obviously, I want to know for certain that the item didn't exist when I attempted to get it, so that it never overwrites existing data.
Am I correct in assuming $result["Item"] === null if and only if the item did not exist in the database at the time of the request? That is, if the item existed prior to the request, will this condition always evaluate to false, regardless of API errors, etc.? Or is there something else I should check for instead?
$result = $this->client->getItem(
array(
"TableName" => $tableName,
"Key" => array(
$keyName => array(Type::STRING => $key),
)
)
);
if ( $result["Item"] === null )
{
//Item does not exist; create it and write it to dynamoDb (code not shown)
}
return $result["Item"];

I would add 'ConsistentRead' => true in order to make sure your read is getting the absolute, most up-to-date data.
You are still going to have a potential race condition here where if multiple processes try to get the item and see that it is not there, then they will all try to write the item, but only one process won't have its data clobbered. As long as there is no chance that they will write different data, then it doesn't matter.

Consider a conditional put where you specify that the key must not exist before doing the put. This avoids any race condition, and takes only a single call. The only downside is that you must send the entire new item over the wire, even if it already exists.
Scroll down to the "specifying optional parameters" section here: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/LowLevelJavaItemCRUD.html#PutLowLevelAPIJava
The code should look something like this:
// Optional parameters Expected and ReturnValue.
Map<String, ExpectedAttributeValue> expected = new HashMap<>();
expected.put(
"hashKeyAttributeName",
new ExpectedAttributeValue()
.withValue(new AttributeValue().withS("hashKeyValue"))
.withExists(false)
);

Related

Laravel unique validation with slug

I have two options, either the users gives a custom unique_id and I convert it via Str::slug($request->custom) or it gets generated via Str::random(6)
My code:
$post = new Post;
$unique_id = Str::random(6);
$idcustom = Str::slug($request->custom);
$this->validate($request, [
'custom' => 'max:25|string|unique:posts,unique_id' . Str::slug($post->unique_id),
]);
If the user creates the custom id, $idcustom gets inserted into the database, if he just leaves the field empty $unique_id gets inserted. But if there is already an entry with for example "stack overflow" I get an SQL error, that there is already an entry with that name, but if its like "stackoverflow" it works like it should. So it has to do with the slug, what am I doing wrong here?
I don't think you can put 'fallback' values into the validation rules. You'd perhaps want to check $request->custom manually before swapping it with your random string?
Not sure whether this'll help... your question is not clear on whether you're creating a new user or updating an existing one. If updating an existing one, don't forget to exclude from checking against the current user:
'custom' => ['max:25', 'string',
Rule::unique('users')->ignore($user->id)],

Magento - API not being updated

The previous provider killed several kittens by changing the core many times of a Magento 1.6.2.0 distribution.
So, in order to solve an issue in record time, we had to screw and hit the kittens' corspses: we still maintain the modified API: catalog_category.assignProduct.
So far, we have this API for the method:
public function assignProduct($categoryId, $productId, $position = null, $identifierType = null)
{
$datos = explode('|', $categoryId);
$productId = array_shift($datos);
$categorias_actuales = Mage::getModel('catalog/category')
->getCollection()
->addIsActiveFilter()
->addIdFilter($datos)
->addLevelFilter(3)
->getAllIds();
$incat = function($cat) use ($categorias_actuales) {
return in_array($cat, $categorias_actuales);
};
$result = array_combine($datos, array_map($incat, $datos));
try {
$product = Mage::helper('catalog/product')->getProduct($productId, null, $identifierType);
$product->setCategoryIds($categorias_actuales);
$product->save();
} catch (Mage_Core_Exception $e) {
$this->_fault('data_invalid', $e->getMessage());
} catch (Exception $e) {
$this->_fault('internal_error', $e->getMessage());
}
return $result;
}
The intention of the API was to assign many categories at once for a product. However this is a modified version because the previous was prohibitively slow. And the curious fact is that this worked until recently. It's intention was to:
only the first parameter is used, and instead of an integer value, a kitten was killed here and the API now expects a string like "productId|catgId1|catgId2|cargId3|..." where the first value is a product id and the second to last values are categories ids; each of them being integer values. The parameter is broken by pipe character ("|") and the product id is popped. In this way, we have the product id in one var, and the categories array in another var.
get the categories collection keeping only the active ones in level 3 (i.e. depth for the category in the tree) whose ids are among the specified ones. This means: if provided categories are array(3, 5, 7, 8) (e.g. from a "245|3|5|7|8" parameter, being "245" the product id) and one of them does not exist or is not active (e.g. 7 is not active and 8 does not exist), the returned value in $categorias_actuales is [3, 5].
as for debugging porpuse, map each input category to existence and validity. this means: existent&&active&&level=3 categories will have "true" as value, while non-existent or non-active categories will have "false" as value. For the given example, the returned array would be: array(3 => true, 5 => true, 7 => false, 8 => false), since 7 is not active and 8 does not exist.
in the try-catch block: a. retrieve the product; b. set the filtered ids (in the example: [3, 5]) as product categories in the just-fetched product; c. save the product.
However, I have the following issues:
The function returns true, so returning $result would not give me the array $results as return value (my intention was to know in which categories was the product actually inserted).
Changing to false instead of $result in the return statement had no effect at all: the obtained/displayed value from the API call was still true.
Throwing a new Exception("something's going on here") had no effect at all. Still true at output.
dying (die('something's going on here')) neither had effect. Still seeing (guess what?) true at the output.
Edit: Also tried a syntax error!! (guess what? nothing happens).
It's not only that I tried these steps, but also refreshed the cache (System > Cache Management > select all and refresh, and even clicking the "Flush Magento Cache" button).
Questions:
1. given the issues before: how can I debug that API call?
2. what could be causing the product not being saved with their categories? By calling category.level I can see that the given ids (i.e. given in the first parameter to category.assignProduct) exist.
I'm a n00b # magento API and perhaps I'm missing something usually obvious. Any help would be appreciated.
Did you disable compilation? You can do it in one of these two ways.
System -> Tools -> Compilation in admin
Use SSH/shell and navigate to your magento root. Do the following commands:
cd shell
php -f compiler.php disable
Also, if your web server runs PHP APC with apc.stat set to 0 (you can check this by running php -i | grep apc.stat or looking for it at any phpinfo() output), please restart your apache2 web server or if you use php5-fpm -- restart that one, too.
Then, if all else fails, try looking for an equivalent file at app/code/local.
e.g. if your file is somewhere in app/code/core/Mage/Path/ToApiFile.php, look for the local version at app/code/local/Mage/Path/ToApiFile.php.
Finally, a very useful shell command for searching code instances:
$ cd app/code/
$ grep -rin "function assignProduct" *

Yii mass assignment from $_GET not working as expected

I'm trying to perform a mass assignment of 2 variables I'm sending via GET to another model::controller (from project::actionCreate to client::actionCreate)
In the _form view for project::actionCreate I've got the following:
<?php echo " ".Chtml::link('+New client',array('client/create',array('Client' => array('redir'=>Yii::app()->controller->route,'redirId'=>$model->id))));?>
With the goal of creating an array "Client" with attributes "redir" and "redirId".
In client::actionCreate I want to do something like
if(isset($_GET['Client']))
{
$model->attributes=$_GET['Client'];
}
Now I noticed that my $_GET var puts client inside subarray 0, so I've tried this with
$_GET[0]['Client']
as well, but no luck. However if I manually assign the variables like this:
$model->redir = $_GET[0]['Client']['redir'];
$model->redirId = $_GET[0]['Client']['redirId'];
Then it works.
Any idea what is up? The goal is to allow someone to create a new client while creating/updating a project record, by sending them to client::actionCreate, but redirecting them back to their original project::actionCreate if they were linked there from my "+New Client" link.
I think the client array is put inside subarray 0 because you've added an array around the parameters. Try removing the array like the following:
<?php
Chtml::link('+New client',array('client/create', 'Client' => array('redir'=>Yii::app()->controller->route,'redirId'=>$model->id)));
?>
I don't know what your model looks like but if the fields aren't assigned they are probably not safe. You can make them safe by adding them to the rules part of your model. Or you could try the following, by specifying the false parameter it will be possible to assign values to unsafe attributes. (http://www.yiiframework.com/doc/api/1.1/CModel#setAttributes-detail)
$model->setAttributes($_GET['Client'], false);
I am not sure creating a link like you want is possible. I have asked something similar some time ago Yii link with [ as a parameter I just could never get the link to how I wanted it. In the end I just created the link the old fashion way, not using CHTML.

Three JSON strings in one AJAX request conflicting in Zend

I have three different request for my ajax:
$result = Map_Model_Map_Factory::getCityByRegionAlias($alias);
$resultCountUsers = User_Model_User_Factory::countUserByRegion($alias);
$resultCountPartners = User_Model_User_Factory::countPartnersByRegion($alias);
First request works pretty well. But second and third conflicts with each other. If $this->_helper->json($resultCountUsers); comes first, then it works:
$this->_helper->json($resultCountUsers);
$this->_helper->json($resultCountPartners);
$this->_helper->json($result);
I get what I need countUsers: "1" but I don't have countPartners. And vice versa, if $this->_helper->json($resultCountPartners); comes first, then I get countPartners without countUsers.
Maybe somebody know, what's going on and how I can receive that.
I don't use Zend, but there is clearly a problem: you are not providing attribute names for the JavaScript object. I wonder whether you are overwriting each response with the next one.
See what effect this has in your AJAX viewer:
$this->_helper->json(
array(
'resultCountUsers' => $resultCountUsers,
'resultCountPartners' => $resultCountPartners,
'result' => $result,
)
);

How to mail to a static list segment with mailchimp API

Once I've identified identified the email addresses of my list segment (using get_emails() custom function, I am setting up my list segment as follows:
$batch = get_emails();
//now create my list segment:
$api->listStaticSegmentAdd(WEDDING_LIST_ID, 'new_wedding_guests');
$api->listStaticSegmentMembersAdd(WEDDING_LIST_ID, 'new_wedding_guests', $batch);
//do I build vars for a campaign?
$options = array (
'list_id' => WEDDING_LIST_ID, //What value id's my list segment?
'subject' => 'Alpha testing.',
'from_email' => 'wedding#juicywatermelon.com',
'from_name' => 'Pam & Kellzo',
'to_name' => $account->name,
);
From here can I use a basic campaign and send it?
$content['text'] = "Some text.";
$content['html'] = get_link($account);
$cid = $api->campaignCreate('regular', $options, $content);
$result = $api->campaignSendNow($cid);
I'm not sure if I'm understanding the api documentation correctly. I also tried 'list_id' => 'new_wedding_guests'; which failed to create a campaign.
Thanks!
I'll assume this is test code and just make the cursory mention of how you probably don't need to be creating a new Static Segment every time. However, your call to add members is not going to work. Per the listStaticSegmentMembersAdd documentation, you should be passing the static segment id, not the name of it. Also note that the docs cross-reference themselves when input params can come from other calls - that parameter there is a good example (it also happens to be returned by listStaticSegmentAdd).
Your options for campaignCreate look like a good start. The documentation for it has examples below - those examples are included in the PHP MCAPI wrapper you likely downloaded. As per above, the list_id you need is the one for the list you used in the listStaticSegment calls (also linked in the documentation).
Now the real key - further down in the campaignCreate docs is the segment_opts parameter - that is how you control segmentation. Follow the link it gives you and you'll find tons of info on the ways you can do segmentation, including using a static_segment.
Hopefully all of that made sense, if not, take a step back and check out these links (and play with segmentation in the app), then it should:
Introduction to MailChimp List Management
How can I send to a segment of my list?
Our Release Info on how Static Segments are used

Categories