我正在尝试根据多种不同因素计算产品成本。我的系统目前使用PHP函数完美运行,但我想添加一些Ajax以产生更友好的用户体验。
//entity/ProductRecipe.php
public function productcost2amountcost() {
$this->productcost = null;
$am = $this->amount;
$cu = $this->product->getCostunit();
$productcost = $am * $cu;
$this->productcost = $productcost;
$this->recipe->fixRecipecost();
$this->recipe->fixCostperyield();
}
//entity/Recipe.php
public function fixRecipecost() {
$this->recipecost = 0;
foreach ($this->product AS $pc) {
$this->recipecost += $pc->getProductcost();
$this->setRecipecost($this->recipecost);
}
}
public function fixCostperyield(){
$this->costperyield = null;
$cy = $this->recipeyield;
$rc = $this->recipecost;
$this->costperyield = $rc / $cy;
}
//Form/RecipeType.php
$builder
->add('recipename', 'text', array(
'label' => 'Recipe Name'))
->add('recipeyield', 'number', array(
'label' => 'Recipe Yield'))
->add('product', 'collection', array(
'label' => 'Ingredients',
'type' => new ProductRecipeType(),
'allow_add' => true,
'by_reference' => false,
'allow_delete' => true,
));
//Form/ProductRecipeType.php
$builder
->add('product', 'entity', array(
'class' => 'BCInventoryBundle:Product',
'property' => 'prodlist',
))
->add('amount', 'number', array(
'label'=>'Quantity',
))
->add('measure', 'entity', array(
'class' => 'BCInventoryBundle:Measures',
'property' => 'unit',
))
->add('productcost' ,'money', array(
'currency' => false,
'read_only' => 'true',
))
;
正如我之前所说,一切都很好,虽然有点无聊和静止。
从图片中可以看出。 ProductRecipe用作Recipe表单中的表单集合。我想要的是,一旦用户从数据库(Butter)中选择了一个产品并说明了数量(1)和度量(kg)我需要Ajax才能首先获得UnitCost(所有单位都转换为Grams并更新名为Unitcost的文件) )
1kg转换为g = 1000,1000 * unitcost(0.0079600000)= £7.96 < - 需要将其放入表单的ProductCost字段中。
任何帮助都会受到极大的赞赏,即使正确方向上的一点也会令人惊叹。我花了几个小时谷歌,但出现的东西似乎永远不是我需要的,特别是涉及Symfony2时。
如何使用Ajax运行productcost2amountcost()函数,以便在没有页面刷新的情况下填充ProductCost字段。
提前谢谢你。道格。
感谢Santiag00经过多次试验和错误后,我们都得到了它的工作。他已经更新了他的部分,但我想详细说明一下。
//Calc.js
$(document).on('change', '.products, .amounts, .unit', function(event) {
var amount = $(this).parent().parent().parent().find('.amounts').val();
var productId = $(this).parent().parent().parent().find('.products').val();
var unit = $(this).parent().parent().parent().find('.unit').val();
var productCostField = $(this).parent().parent().parent().find('.product-costs');
//The above assign a Var to each of the field's needed for the JS
console.log(productCostField);
console.log("Amount: " + amount + " - ProductID: " + productId + " - unit: " + unit);
if (amount == "" || productId == "" || unit == "") {
// Don't make the Ajax call if you are missing one of the two values
return false;
}
// This will be triggered every time a product or amount input field is changed
$.post(
Routing.generate('calculate_cost'),
//This line is what connects to the Function in the controller and defined in routing.yml. Made easier by
//https://github.com/FriendsOfSymfony/FOSJsRoutingBundle/blob/master/Resources/doc/index.md
{
// Use the corresponding amount and product ID
product: productId, amount: amount, unit: unit,
},
function(data) {
data = JSON.parse(data);
if (!data.success) {
// An error was thrown in the controller
alert(data.message);
}
else {
// Update the corresponding productCost field using the data from the controller
console.log("Product cost: " + data.productCost);
productCostField.val(data.productCost);
}
}
);
}
);
//routing.yml
calculate_cost:
pattern: /productcost
defaults: { _controller: "BCInventoryBundle:ProductRecipe:getProductCost" }
options:
expose: true
//ProductRecipeController.php
public function getProductCostAction(Request $request) {
$amount = $request->request->get('amount', null);
$productId = $request->request->get('product', null);
$unit = $request->request->get('unit', null);
if (empty($amount) || empty($productId)) {
return new \Symfony\Component\HttpFoundation\Response(json_encode(array('success' => false, 'message' => 'Bad input')));
}
$em = $this->getDoctrine()->getManager();
$product = $em->getRepository('MyBundle:Product')->find($productId);
$u = $em->getRepository('MyBundle:Measures')->find($unit);
$mass = new Mass($amount, $u->getUnit());
$fam = $mass->toUnit('g');
if (empty($product)) {
return new \Symfony\Component\HttpFoundation\Response(json_encode(array('success' => false, 'message' => 'Invalid product')));
}
$productCost = $product->getCostunit() * $fam;
return new \Symfony\Component\HttpFoundation\Response(json_encode(array('success' => true, 'productCost' => $productCost)));
}
我真的希望这对其他人有帮助。如果你发现它很有用,那么我们花了很多时间试图解决这个问题。要注意的主要部分是我们如何选择字段,因为它们在Symfony中使用嵌入表单时的嵌套方式。
答案 0 :(得分:1)
productcost2amountcost看起来太复杂了,它与模型的状态有很强的关系。
如果您想在每次客户端发送Ajax请求时更新DB(或某些商店),您可以使用productcost2amountcost。但它既昂贵又有风险。 (您必须控制请求的顺序)[Solution1]
如果您想更简单地处理请求,我认为您应该将productcost2amountcost转换为无状态(作为过程)和一些小逻辑。 (由客户管理的国家)[解决方案2]
新程序通过ajax接收一些参数(例如产品,数量,量度),并发送响应(例如productcost)
(如果你使用临时模型(非存储),你可以使用productcost2amountcost。但你应该从productcost2amountcost删除对食谱的引用)
但在这种情况下,我认为你不必使用ajax。
您可以通过javascript计算所有成本与表单数据(包括隐藏单位成本和度量标度)的可用性,并在服务器端重新计算以便最后更新。 [Solution3]
不同架构的逻辑复制和计算都很糟糕,但它可能是简单的解决方案。
答案 1 :(得分:1)
一种解决方案是安装“FOSJsRoutingBundle”(https://github.com/FriendsOfSymfony/FOSJsRoutingBundle)以在Javascript中公开路线。这样,您就可以在Controller中创建一个新操作,用于计算产品成本并将其作为JSON返回给HTML。
控制器中的操作可能如下所示:
/**
* @Route("/productcost", name="calculate_cost", options={"expose"=true})
* @Method("POST")
*/
public function getProductCostAction(Request $request) {
$amount = $request->request->get('amount', null);
$productId = $request->request->get('product', null);
if (empty($amount) || empty($productId)) {
return new \Symfony\Component\HttpFoundation\Response(json_encode(array('success' => false, 'message' => 'Bad input')));
}
$product = $this->getDoctrine()->getManager()->getRepository('ProductBundle:ProductRecipe')->findOneBy(array('id' => $productId));
if (empty($product)) {
return new \Symfony\Component\HttpFoundation\Response(json_encode(array('success' => false, 'message' => 'Invalid product')));
}
$productCost = $product->getCostunit() * $amount;
return new \Symfony\Component\HttpFoundation\Response(json_encode(array('success' => true, 'productCost' => $productCost)));
}
然后AJAX调用看起来像这样:
<script>
$(document).on('change', '.products, .amounts', function(event) {
var amount = $(this).parent().children('.amounts').val();
var productId = $(this).parent().children('.products').val();
if (amount == "" || productId == "") {
// Don't make the Ajax call if you are missing one of the two values
return false;
}
// This will be triggered every time a product or amount input field is changed
$.post(
Routing.generate('calculate_cost'),
{
// Use the corresponding amount and product ID
amount: amount,
product: productId
},
function(data) {
data = JSON.parse(data);
if (!data.success) {
// An error was thrown in the controller
alert(data.message);
}
else {
// Update the corresponding productCost field using the data from the controller
$(this).parent().children('.product-costs').val(data.productCost);
}
}
);
});
</script>