(sorry for my english)
I have a little problem.
Shop Bascket
I want to store at session a shop-bascket, so I created the php/classes/bascket.php:
class Product
{
private $id;
private $quantity;
function __construct(int $id, int $q)
{
$this->id = $id;
$this->quantity = $q;
}
...
}
class Bascket
{
private $products = array();
/* for testing */
function __construct()
{
$this->products[] = new Product(26, 1006);
}
function add(int $id, int $quantity)
{
...
}
function delete(int $id, int $quantity)
{
...
}
function __get($field) {
return $this->$field;
}
}
Using the Shop Bascket
And I use this class on session anywhere I want:
include "php/classes/bascket.php"; (*or another correct path*)
session_start();
if(!isset($_SESSION["bascket"])) {
$_SESSION["bascket"] = serialize(new Bascket());
}
$bascket = unserialize($_SESSION["bascket"]);
Trying to display Bascket Shop with Ajax
Because I want to show the bascket on pressing a button, I made an ajax which do the following thing:
function display_bascket() {
$.ajax({
url: 'php/take_bascket.php',
dataType: 'text',
cache: false,
contentType: false,
processData: false,
type: 'post',
success: function(bascket){
//bascket = JSON.parse(bascket);
//bascket = jQuery.parseJSON(bascket);
$("#content").html(bascket);
}
});
}
And I tried a lot to can display the correct thing in take_bascket.php to receive a good array, or a json in ajax.
take_bascket.php
<?php
session_start();
include "classes/bascket.php";
if(!isset($_SESSION["bascket"])) {
$_SESSION["bascket"] = serialize(new Bascket());
}
// I tried many variants:
var_dump($_SESSION["bascket"]);
/*
* output:
* string(116) "O:3:"Bascket":1:{s:12:"Bascketproducts";a:1:{i:0;O:6:"Product":2:{s:10:"Productid";i:26;s:17:"Productquantity";i:1006;}}}"
*
* and I don't know how to handled it in ajax to get the products array
*/
var_dump(unserialize($_SESSION["bascket"]));
/*
* output:
* object(Bascket)#1 (1) { ["products":"Bascket":private]=> array(1) { [0]=> object(Product)#2 (2) { ["id":"Product":private]=> int(26) ["quantity":"Product":private]=> int(1006) } } }
*
* and I don't know how to handled it in ajax to get the products array
*/
var_dump(json_encode($_SESSION["bascket"]));
/*
* output:
* string(158) ""O:3:\"Cos\":1:{s:12:\"\u0000Cos\u0000products\";a:1:{i:0;O:6:\"Product\":2:{s:10:\"\u0000Product\u0000id\";i:26;s:17:\"\u0000Product\u0000quantity\";i:1006;}}}""
*
* and I don't know how to handled it in ajax to get the products array
*/
var_dump(((unserialize($_SESSION["bascket"]))->products));
/*
* output:
* array(1) { [0]=> object(Product)#2 (2) { ["id":"Product":private]=> int(26) ["quantity":"Product":private]=> int(1006) } }
*
* and I don't know how to handled it in ajax to get the products array
*/
var_dump(((unserialize($_SESSION["bascket"]))->products[0]));
/*
* output:
* object(Product)#2 (2) { ["id":"Product":private]=> int(26) ["quantity":"Product":private]=> int(1006) }
*
* and I don't know how to handled it in ajax to get the products array
*/
Conclusion
As you can see I also tried different ways of manipulate the output in ajax. But or it is a string and I can't convert it in array. Or I can't make it json, etc.
Please
Please, can you try find a complete solution? I mean for take_bascket.php, but also for what I have to do in display_bascket() in js.
thank you in advance
Edit:
I did as someone said in a post:
php/classes/bascket.php
<?php
class Product
{
private $id;
private $quantity;
function __construct(int $id, int $q)
{
$this->id = $id;
$this->quantity = $q;
}
function decrease(int $value)
{
...
}
function increase(int $value) {
...
}
public function toArray(){
return [
'id' => $this->id,
'quantity' => $this->quantity,
];
}
}
class Bascket
{
private $products = array();
/* for testing */
function __construct()
{
$this->products[] = new Product(26, 1006);
}
function add(int $id, int $quantity)
{
...
}
function delete(int $id, int $quantity)
{
...
}
public function toJson(){
$products = [];
foreach ($this->products as $product) {
$products[] = $product->toArray();
}
return json_encode(
[
'products' => $products
],
JSON_PRETTY_PRINT
);
}
function __get($field) {
return $this->$field;
}
}
And that's how I would theoretical create a PHP JSON easier.
But look at take_bascket.php:
<?php
session_start();
include "classes/bascket.php";
if(!isset($_SESSION["bascket"])) {
$_SESSION["bascket"] = serialize(new Bascket());
}
var_dump(((unserialize($_SESSION["bascket"]))->toJson()));
/*
* output:
* string(98) "{ "products": [ { "id": 26, "quantity": 1006 } ] }"
*/
Trying to use it in display_bascket():
function display_bascket() {
$.ajax({
url: 'php/take_bascket.php',
dataType: 'text',
cache: false,
contentType: false,
processData: false,
type: 'post',
success: function(bascket){
//bascket = JSON.parse(bascket);
$("#content").html(bascket);
}
});
}
If I don't use JSON.parse(), it'll display the next plain text:
string(98) "{ "products": [ { "id": 26, "quantity": 1006 } ] }"
Instead, if I use JSON.parse(), I have a console error:
Uncaught SyntaxError: Unexpected token s in JSON at position 0
at JSON.parse (<anonymous>)at Object.success (display_bascket.js:10)
at j (jquery.js:2) at Object.fireWith [as resolveWith] (jquery.js:2)
at x (jquery.js:4) at XMLHttpRequest.b (jquery.js:4)
What should I do?
I suggest that in each object you create a method that will return a JSON representation of that object.
For instance (filename: products.php):
class Product {
private $name;
private $value;
private $quantity;
public function __construct($name, $value, $quantity){
$this->name = $name;
$this->value = $value;
$this->quantity = $quantity;
}
public function toArray(){
return [
'name' => $this->name,
'value' => $this->value,
'quantity' => $this->quantity,
];
}
}
class Basket{
private $products = [];
public function addProduct(Product $p){
$this->products[] = $p;
}
public function toJson(){
$products = [];
foreach ($this->products as $p) {
$products[] = $p->toArray();
}
return json_encode(
[
'products' => $products
],
JSON_PRETTY_PRINT
);
}
}
$b = new Basket();
$b->addProduct(new Product('Apple', 1, 5));
$b->addProduct(new Product('Banana', .5, 2));
$b->addProduct(new Product('Carrots', .35, 6));
echo $b->toJson();
This will generate a JSON object that you can use with jQuery .getJSON() method.
Like the example below (filename: products.html):
<html>
<head>
<script src="https://code.jquery.com/jquery-3.2.1.min.js"> </script>
</head>
<body>
<h3>Product list</h3>
</body>
<script>
$(function(){
$.getJSON( "products.php", function( data ) {
console.log(data);
var items = [];
$.each( data.products, function( key, val ) {
items.push( "<li>Name: " + val.name + " | Quantity: " + val.quantity + " | Price: " + val.value + "</li>" );
});
$( "<ul/>", {
html: items.join( "" )
}).appendTo( "body" );
});
});
</script>
</html>
Related
// LocalStorage is a lowdb adapter for saving to localStorage
const adapter = new LocalStorage('db')
// Create database instance
const db = low(adapter)
// Set default state
db.defaults({ items: [] })
.write()
Now how it can be saved where it's hosted like in './maindb.json'?
Is there anything available like FileSync?
Update
after realising there no way that client can access server filesystem. I probably asked a wrong question. but there is a solution using fetch. so if anyone has ans please put it down I am trying my best.
index.html -> fetch(jsonObj) -> post -> save.php-> creates maindb.json/updates.
index.html -> fetch() -> get -> save.php -> returns from maindb.json.
Controller.php
<?php
class Controller {
private $file = 'data.json',
$jsondata = null,
$tempArray = array(),
$data= array();
public function __construct() {
$this->init();
}
private function init(){
if (!file_exists($this->file)) {
touch($this->file);
$this->read();
}else{
$this->read();
}
}
private function read(){
$this->jsondata = file_get_contents($this->file);
$this->tempArray = $this->jsondata != null ? json_decode($this->jsondata): array();
}
private function write(){
array_push($this->tempArray, $this->data);
$this->jsondata = json_encode($this->tempArray);
file_put_contents($this->file, $this->jsondata);
}
public function push($data){
$this->data = $data;
if($this->data){
$this->write();
return true;
}
}
public function get(){
$this->read();
return json_encode($this->tempArray);
}
}
?>
json.php
<?php
require 'Controller.php';
$db = new Controller;
if($db->push($_POST['data'])){
echo $db->get();
}
?>
javascript
function post(input){
var data = {'data': input}
$.ajax({
type: 'POST',
url: 'json.php',
dataType: 'json',
data: data,
success: function(data) {
console.log(data)
}
});
}
I am totaly stuck with an Ajax request. I m trying to send a response to Ajax with an encoded array to json. Ajax get a status 200 response, but only strings are sent ; not my variables.
I wonder if the probleme is due to the asynchronous... When I test with Postman, i can see the full response but Js give to me : {"recipies":[]}.
Thanks for your help.
Ajax :
searchByIngredients: function () {
console.log('Search for recipies');
var array = [];
var ingredients = $('.span-ingredient');
ingredients.each(function () {
array.push(this.innerHTML);
});
console.log(array);
console.log(Array.isArray(array));
$.ajax(
{
url: Routing.generate('shopping_list_by_ingredients_ajax'),
type: "POST",
contentType: "application/json",
dataType: "json",
data: JSON.stringify(array)
}).done(function (response) {
if (null !== response) {
console.log('ok : ' + JSON.stringify(response));
console.log(typeof(response));
} else {
console.log('Error');
}
}).fail(function (jqXHR, textStatus, error) {
console.log(jqXHR);
console.log(textStatus);
console.log(error);
});
}
};
Controller :
/**
* #Route("/by-ingredient-ajax", name="shopping_list_by_ingredients_ajax", options={"expose"=true}, methods={"GET","POST"})
*
* #return JsonResponse|Response
*/
public function createShopplistByIngredientsAjax(Request $request, RecipeIngredientRepository $recipeIngredientRepository, RecipeRepository $recipeRepository)
{
if ($request->isMethod('POST')) {
$dataIngredients = json_decode($request->getContent());
$dataIngredients = $request->getContent();
// Sorry for this :/
$arrayIngredients = explode(', ', $dataIngredients);
$text = str_replace("'", '', $arrayIngredients);
$text2 = str_replace('[', '', $text);
$text3 = str_replace(']', '', $text2);
$recipiesArray = [];
// Get matching RecipeIngredient
foreach ($text3 as $data) {
/**
* #return RecipeIngredient()
*/
$recipeIngredients = $recipeIngredientRepository->findBy([
'name' => $data,
]);
foreach ($recipeIngredients as $recipeIng) {
$name = $recipeIng->getName();
$recipeNames = $recipeRepository->findRecipeByKeywwords($name);
foreach ($recipeNames as $recipeName) {
/**
* #return Recipe()
*/
$recipies = $recipeRepository->findBy([
'id' => $recipeIng->getRecipe(),
]);
// Built array with names & ids of recipies
foreach ($recipies as $key => $recipe) {
$recipeName = $recipe->getName();
$recipeId = $recipe->getId();
$recipiesArray[] = ['name' => $recipeName];
$recipiesArray[] = ['id' => $recipeId];
}
}
}
}
$response = new Response();
$response->setContent(json_encode([
'recipies' => $recipiesArray,
]));
$response->headers->set('Content-Type', 'application/json');
return $response;
}
return new Response(
'Something wrong...',
Response::HTTP_OK,
['content-type' => 'text/html']
);
Repository :
/**
* #return Recipe[] Returns an array of Recipe objects
*/
public function findRecipeByKeywwords($value)
{
return $this->createQueryBuilder('r')
->andWhere('r.name LIKE :val')
->setParameter('val', '%'.$value.'%')
->orderBy('r.id', 'ASC')
->setMaxResults(10)
->getQuery()
->getArrayResult();
}
composer require jms/serializer-bundle
After you have installed the package, you just need to add the bundle to your AppKernel.php file:
// in AppKernel::registerBundles()
$bundles = array(
// ...
new JMS\SerializerBundle\JMSSerializerBundle(),
// ...
);
The configured serializer is available as jms_serializer service:
$serializer = $container->get('jms_serializer');
$json=$serializer->serialize(['recipies' => $recipiesArray], 'json');
return new JsonResponse($json,200);
Symfony 2.1
$response = new Response(json_encode(array('recipies' => $recipiesArray)));
$response->headers->set('Content-Type', 'application/json');
return $response;
Symfony 2.2 and higher
You have special JsonResponse class, which serialises array to JSON:
use Symfony\Component\HttpFoundation\JsonResponse;
//
//
return new JsonResponse(array('recipies' => $recipiesArray));
https://symfony.com/doc/current/components/http_foundation.html
When I use select2, the list of choice doesn't reduce while searching, which is pretty annoying when I have more than 50 choices..
I use symfony4 framework, with a route providing my tags that are in a DB:
/**
* #Route("/miseenpage/keywords.json", name="keywords", defaults={"_format": "json"})
*/
Then I init my select2 with this code provided by the symfony Tags plugin:
$( document ).ready(function() {
initTags($('input[name$="[tagsText]"]'));
});
// TAGS
function initTags($input) {
if($input.length) {
$input.attr('type', 'hidden').select2({
width: '85%',
tags: true,
tokenSeparators: [","],
createSearchChoice: function (term, data) {
if ($(data).filter(function () {
return this.text.localeCompare(term) === 0;
}).length === 0) {
return {
id: term,
text: term
};
}
},
multiple: true,
ajax: {
url: $input.data('ajax'),
dataType: "json",
data: function (term, page) {
return {
q: term
};
},
results: function (data, page) {
return {
results: data
};
}
},
initSelection: function (element, callback) {
var data = [];
function splitVal(string, separator) {
var val, i, l;
if (string === null || string.length < 1) {
return [];
}
val = string.split(separator);
for (i = 0, l = val.length; i < l; i = i + 1) {
val[i] = $.trim(val[i]);
}
return val;
}
$(splitVal(element.val(), ",")).each(function () {
data.push({
id: this,
text: this
});
});
callback(data);
}
});
}
}
Here is the result in my webpage before searching:
Here is after searching:
As you can see, the list is still the same, just the result is underlined. I'd like to filter the result depending on what I search, so I don't have to scroll all the way until I find my underlined term.
As it is the basic working of Select2, I guess there is an configuration problem in my JS.
I instanciated this value on load:
let currentSearch = false;
Then I changed the "AJAX" section of my JS so it loops around the list with the searched value:
ajax: {
url: $input.data('ajax'),
dataType: "json",
data: function (term) {
currentSearch = term;
return {
q: term
};
},
results: function (data) {
let returnTab = [];
data.forEach(function(e) {
if(e.text.includes(currentSearch)){
returnTab.push(e);
}
});
return {
results: returnTab
};
}
},
I'm pretty sure there is a cleaner/simpler way of doing this, but for moment it's a quickfix.
Just a basic example with some code to show how we use Select2 (v4.0.3, 3.5 may be quite different) with Ajax
On a twig, we have for example :
$("#users").css('width', '100%').select2({
minimumInputLength: 3,
ajax: {
url: "{{ path('api_search_user') }}",
dataType: 'json',
delay: 500,
data: function (params) {
return {
needle: params.term // Here we send user input to the controller
};
},
processResults: function (data) {
return {
results: data
};
},
cache: false
}
});
And we have a controller with a function to search for users :
/**
* #Route("/search_users", name="api_search_users")
* #param Request $request
* #return JsonResponse
*/
public function searchUsersAction(Request $request)
{
$needle = $request->get('needle'); // Here we retrieve user input
$users = $this->get(User::class)->searchUsers($needle);
return new JsonResponse($users );
}
EDIT following you last comment
This value is not valid
That's because your value isn't part of the select when the formbuilder add the field. You must add an addEventListener on PRE_SUBMIT to dinamically add this value. You can do it this way :
// Define form modifier
$usersFormModifier = function (FormInterface $form, $users) use ($options) {
$choices = array();
if(is_array($users)) {
$choices = $users;
}
$form->add(
'users',
EntityType::class,
array(
'label' => 'conversation.form.users',
'multiple' => true,
'class' => 'AppBundle\Entity\Security\User',
'choices' => $choices,
'choice_label' => function (User $user) {
return $user->getLastName() . " " . $user->getFirstName();
},
'attr' => array(
'placeholder' => 'default.search_person'
)
)
);
};
// On PRE_SET_DATA, we load users from our object (which only contains their IDs)
$builder->addEventListener(
FormEvents::PRE_SET_DATA,
function (FormEvent $event) use ($usersFormModifier) {
$usersFormModifier($event->getForm(), $event->getData()->getUsers()->toArray());
}
);
// On PRE_SUBMIT, we add the options, so the select will accept newly added values
$builder->addEventListener(
FormEvents::PRE_SUBMIT,
function (FormEvent $event) use ($usersFormModifier) {
$data = $event->getData();
$users = null;
if(isset($data['users'])) {
$users = $this->entityManager->getRepository('AppBundle:Security\User')->findBy(array('id' => $data['users']));
}
$usersFormModifier($event->getForm(), $users);
}
);
As I said at the beginning, if you don't have so muchs tags, and they don't evolve regularly, you can construct your select with all your tags and avoid all the Ajax part of the Select2 javascript code ! (I think it will be easier and sufficient for your case)
I'm using the following Javascript to get data via PHP (upload.php) -
<script src="js/jquery.amsify.suggestags.js"></script>
<script>
fetch('./get_hashtags.php').then(response => {
return response.json();
}).then(data => {
var suggestionsArr = [];
data.forEach(function(item){
suggestionsArr.push(item.category);
});
console.log(suggestionsArr);
$('#inputTags').amsifySuggestags({
suggestions: suggestionsArr,
classes: ['bg-warning','bg-warning'],
});
}).catch(err => {
console.log(err);
});
</script>
get_hashtags.php
<?php
// ... some additional database connection details ...
$statement = $pdo->prepare("SELECT category FROM hashtags where active=1");
$hashtags = array();
if ($statement->execute()) {
while ($row = $statement->fetch(PDO::FETCH_ASSOC)) {
$hashtags[] = $row;
}
}
$pdo = null;
echo json_encode($hashtags);
?>
Unfortunately I'm getting the following error when loading the page -
TypeError: $(...).amsifySuggestags is not a function
at fetch.then.then.data (upload.php:1550)
This is the beginning of jquery.amsify.suggestags.js (https://github.com/amsify42/jquery.amsify.suggestags) -
(function($) {
$.fn.amsifySuggestags = function(options, method) {
/**
* Merging default settings with custom
* #type {object}
*/
var settings = $.extend({
type : 'bootstrap',
tagLimit : 5,
suggestions : [],
classes : [],
backgrounds : [],
colors : [],
whiteList : false,
afterAdd : {},
afterRemove : {},
}, options);
/**
* Initialization begins from here
* #type {Object}
*/
var AmsifySuggestags = function() {
this.selector = null;
this.name = null;
...
I don't get the error message when inserting the $('#inputTags').amsifySuggestags outside of the fetch method with some hardcoded values.
Thanks in advance!
I am trying to populate DataTable with my Data but DataTable is showing object in columns and not printing the actual values!
Function in Controller:
public function getEvaluationSymptomsAction() {
//Get Evaluation Symptoms from DataBase
$evaluation_symptoms = CxEbEvaluationSymptom::getAllEvaluationSymptomsWithNameForDataTable();
$inferredRemedies = array();
$additonalRemedies = array();
$data = array();
foreach ($evaluation_symptoms as $key => $symptom) {
$data[ $key ][ 'id' ] = $symptom[ 'id' ];
$data[ $key ][ 'title' ] = $symptom[ 'title' ];
// Get Inferred Remedies By Symptom ID
$inferredRemedies = CxEbEvaluationSymptom::getInferredRemediesBySymptomId($symptom[ 'id' ]);
$additonalRemedies = CxEbEvaluationSymptom::getAdditionalSymptomRemediesBySymptomId($symptom[ 'id' ]);
$data[ $key ][ 'remedy' ] = $inferredRemedies;
$data[ $key ][ 'additional-remedy' ] = $additonalRemedies;
$data[ $key ][ 'date_created' ] = $symptom[ 'date_created' ];
}
//print_r($data);exit;
// Return data array
return array('data' => $data);
// Return data
}
The above function return the below array: (NOTE the below array is var_dump version actually data is in JSON format)
Array code is here
Queries:
public static function getInferredRemediesBySymptomId($symptomId){
$queryBuilder = new Builder();
return $queryBuilder
->from(array('es' => 'Cx\EbFront\Models\Evaluation\CxEbEvaluationSymptom'))
->leftJoin('Cx\EbFront\Models\Evaluation\CxEbEvaluationSymptomCause', 'es.id = esc.evaluation_symptom_id','esc')
->leftJoin('Cx\EbFront\Models\Evaluation\CxEbEvaluationCause','esc.evaluation_cause_id = ec.id','ec')
->leftJoin('Cx\EbFront\Models\Evaluation\CxEbEvaluationCauseRemedy','ec.id = ecr.evaluation_cause_id','ecr')
->leftJoin('Cx\EbFront\Models\Evaluation\CxEbEvaluationRemedy','ecr.evaluation_remedy_id = er.id', 'er')
//->leftJoin('Cx\EbFront\Models\Evaluation\CxEbEvaluationSymptom', 'es.id = :ID:', 'es')
->columns('er.id, er.title')
->where('es.is_active = 1')
->andWhere('es.id = :ID:')
->getQuery()
->execute(array('ID' => $symptomId))
//->execute()->setHydrateMode(Resultset::HYDRATE_ARRAYS)
->toArray();
}
/**
* A
* Data for column Additonal Remedies in DataTable
* #return array
*/
public static function getAdditionalSymptomRemediesBySymptomId($symptomId){
$queryBuilder = new Builder();
return $queryBuilder
->from(array('er' => 'Cx\EbFront\Models\Evaluation\CxEbEvaluationRemedy'))
->innerJoin('Cx\EbFront\Models\Evaluation\CxEbEvaluationSymptomRemedy', 'er.id = esr.evaluation_remedy_id','esr')
->columns('er.id, er.title')
->where('er.is_active = 1')
->andWhere('esr.evaluation_symptom_id = :ID:')
->getQuery()
->execute(array('ID' => $symptomId))
->toArray();
}
The below is the JS code for initializing the DataTable:
function EbEvaluationSymptom(){
var $body = $('body');
var $CxRecordsTable = $('#cx-records-table');
// Init the DatTable using the Cx Admin DataTable plugin
cx.common.data.cxAdminDataTables.EbEvaluationSymptom = $CxRecordsTable.cxAdminDataTable({
ajaxUrl: '<?php echo $this->CxHelper->Route('eb-admin-get-evaluation-symptoms')?>',
columns: [
cx.common.admin.tableEditColumn('id'),
{ data: 'title' },
{ data: 'remedy' },
{ data: 'additional-remedy' },
{ data: 'date_created' }
],
});
};
JSON Response:
https://pastebin.com/g2mhhS4D
DataTables doesn't know how to format the array of object(s) supplied for remedy & additional-remedy.
Assuming there is always one object in each of those arrays, you want to access the first object in each array and use its title property:
columns: [
cx.common.admin.tableEditColumn('id'),
{ data: 'title' },
{ data: 'remedy.0.title' },
{ data: 'additional-remedy.0.title' },
{ data: 'date_created' }
],
If you plan to have more than 1 element in each array, you'll need a different approach