I am trying to use morris area chart dynamicly
from my sql query I get the following result
period | item | amount
------ | ---- | ------
20170801 | iphone | 327
20170801 | ipad | 278
20170801 | ipod | 125
20170802 | iphone | 528
20170802 | ipad | 325
20170802 | ipod | 250
etc
now I need to store this in an array like this
data: [{
period: '20170801',
iphone: 327,
ipad: 278,
ipod: 125
}, {
period: '20170802',
iphone: 528,
ipad: 325,
itouch: 250
}, ...]
I am using a while loop through the table for each date it needs to create a new object. For a date in an object it needs to add an element to that object.
I have absolutely no clue how to achieve this
<?php
class test {
private $period = '';
private $item = '';
private $amount = '';
public function __construct($period, $item, $amount) {
$this->period = $period;
$this->item = $item;
$this->amount = $amount;
}
}
$obj = [
new test('20170801', 'iphone', '327'),
new test('20180801', 'iphone2', '328')
];
var_dump($obj);
But most usefull use ORM and after you get data - serialize it to string via php function "json_encode"
http://php.net/manual/en/function.json-encode.php
http://php.net/manual/en/function.json-decode.php
Ok since you have no idea how to start I coded a little script to get you started:
$db = new mysqli('localhost', 'root', '', 'db');
$result = $db->query('SELECT * FROM table');
$data = $result->fetch_all(MYSQLI_ASSOC);
$json = json_encode($data, JSON_PRETTY_PRINT);
print_r($json);
You have to change the database server data and you table name in SQL query, other then that it should just output the whole table data in JSON format. If you want to join all data from teh same date you have to add soem more logic, but that might cause duplicate properties.
Related
GOAL:
I want to build a "market validation control engine" that validates players' actions and limits on the market.
SUMMARY:
Consider that we have a Character object that can buy only a given number of Item objects, e.g Arrow. The number depends on Race, Tire and Area where a lower layout of hierarchy overrides the upper; if the limit isn't specified lower layout inherits it from the upper:
For example:
Pro ELF in Forest can buy up to 2000 arrows
Basic Ork in Forest and Basic Ork in Desert can buy 50 arrows.
Additionally, the Character object can Buy and Sell a specific amount of arrows on the market. The amount and action depend on the Area. Otherway to say is every node might have its validation rules.
For example:
Basic Elf in Desert can sell 50% arrows
Basic Orc in Desert can sell 100% of the arrows.
Lastly, based on the Tier players can Exchange arrows to another item. For example :
Pro ELF can exchange 100% of its arrows
STRUGGLES:
Building hierarchy
Validation rules. Every layout of hierarchy (Tier or Area) have rules
How to make 1 and 3 work together
Scalability. Adding a new layout (e.g. Clan) or attaching a new validation rule to Area
Maintenance
I am almost sure that I need multiple different patterns here. Currently, I'm thinking of the Decorator Pattern for creating hierarchy object with all the limits and the Chain of Responsibility for the rule validation. However, I am not sure how well these patterns will work together in the long ran.
UPD: In the example, I used Arrow - one of the hundreds of items on the market and Desert with Forest - two of the 9 areas.
There's quite a few different ways to implement this so I'm assuming you're not really sure where to start.
I've written up some example code using classes. In this, there's 2 ways that we could store the item (arrow) data.
Nested Array - This allows for a more "structured" approach. It also allows you to easily add more attributes to each "child" array if necessary.
Serialized Map - This has a much smaller code footprint and is generally quicker.
NOTE: This code is not setup to be well-performing (in reference to speed) but as a way to see how you could setup this system.
There are 3 files here index.php, Character.class.php, Market.class.php.
There are 2 main methods on the Market class: getNestedLimit() and getSerializedLimit(). Each one shows how you would get the limit based on those example structures.
<?php
// index.php
require_once __DIR__ . "/Character.class.php";
require_once __DIR__ . "/Market.class.php";
$market = new Market;
$orc_a = new Character("orc", "basic", "desert");
$orc_b = new Character("orc", "pro", "forest");
$market->getNestedLimit($orc_a, "arrow"); // 50
$market->getNestedLimit($orc_b, "arrow"); // 150
$elf_a = new Character("elf", "pro", "forest");
$elf_b = new Character("elf", "pro", "desert");
$market->getSerializedLimit($elf_a, "arrow"); // 2000
$market->getSerializedLimit($elf_b, "arrow"); // 50
<?php
// Character.class.php
class Character {
public string $race;
public ?string $tier = null;
public ?string $area = null;
public function __construct(
string $race,
?string $tier = null,
?string $area = null,
) {
$this->race = $race;
$this->tier = $tier;
$this->area = $area;
}
}
// Market.class.php
class Market {
public $nested_items = [
"arrow" => [
"limit" => [
"_base" => 0,
"race" => [
"orc" => [
"_base" => 50,
"tier" => [
"basic" => [
"area" => [],
],
"pro" => [
"area" => [
"desert" => 50,
"forest" => 150,
],
],
],
],
"elf" => [
"_base" => 1000,
"tier" => [
"basic" => [
"area" => [
"desert" => 150,
"forest" => 1000,
],
],
"pro" => [
"area" => [
"desert" => 50,
"forest" => 2000,
],
],
],
],
],
],
],
];
public function getNestedLimit(Character $character, string $item_id) {
$item = $this->nested_items[$item_id];
$item_limit = $item["limit"];
$actual_limit = $item_limit["_base"];
// check race
if (isset($item_limit["race"][$character->race])) {
$race_limit = $item_limit["race"][$character->race];
if (isset($race_limit["_base"])) {
// value exists - use this
$actual_limit = $race_limit["_base"];
}
// check tier
if (isset($race_limit["tier"][$character->tier])) {
$tier_limit = $race_limit["tier"][$character->tier];
if (isset($tier_limit["_base"])) {
// value exists - use this
$actual_limit = $tier_limit["_base"];
}
// check area
if (isset($tier_limit["area"][$character->area])) {
$actual_limit = $tier_limit["area"][$character->area];
}
}
}
return $actual_limit;
}
/** Serialize syntax:
* {race}[-{tier}[-{area}]]
* e.g.
* "Pro tier orc in forest" -> "o-p-f"
* "Basic tier elf" -> "e-b"
* "Orc" -> "o"
*
* When determining the limit, pick the most specific first.
*/
public $serialized_items = [
"arrow" => [
"limit" => [
"_base" => 0,
// orc
"o" => 50,
"o-p-d" => 50,
"o-p-f" => 150,
// elf
"e" => 1000,
"e-b-d" => 150,
"e-b-f" => 1000,
"e-p-d" => 50,
"e-p-f" => 2000,
]
]
];
/** This "map" is purely for example - you may end up using ids
* or something more consistent.
* I would recommend using a different system, such as enums or constants.
*/
public $serial_keys = [
"orc" => "o",
"elf" => "e",
"basic" => "b",
"pro" => "p",
"desert" => "d",
"forest" => "f",
];
public function getSerializedLimit(Character $character, string $item_id) {
$item = $this->serialized_items[$item_id];
$item_limit = $item["limit"];
$actual_limit = $item_limit["_base"];
// serialize character
// this could be done in various ways - this is purely for example
// start with most specific
$serial = $this->serial_keys[$character->race] . "-" . $this->serial_keys[$character->tier] . "-" . $this->serial_keys[$character->area];
while ($serial !== "") {
if (isset($item_limit[$serial])) {
$actual_limit = $item_limit[$serial];
break;
}
// remove most specific section
// here we are expected each section to be a single character
// be removing 2 characters, we remove the hyphen as well
// NOTE: this hyphen is only here to help visualize
// you could very easily use 1 character without
// the hyphen and change this to `-1`
$serial = substr($serial, -2);
}
return $actual_limit;
}
}
EDIT: Adding example compiling nested array
As mentioned in the comments, you won't have to manually adjust the array - instead you could have it compile on load/initialise of the market. The code below shows an example datasource setup and code to compile the nested array.
This can also easily be adjusted to re-created the serialized array.
<?php
Datasource: `item`
| item_id | name | limit |
|---------|-------|-------|
| arrow | Arrow | 0 |
Datasource: race
| race_id | `name` |
|---------|--------|
| elf | Elf |
| orc | Orc |
Datasource: `tier`
| tier_id | name |
|---------|-------|
| basic | Basic |
| pro | Pro |
Datasource: `area`
| area_id | name |
|---------|--------|
| forest | Forest |
| desert | Desert |
Datasource: `item_limit`
| item_id | race_id | tier_id | area_id | limit |
|---------|---------|---------|---------|-------|
| arrow | orc | NULL | NULL | 50 |
| arrow | orc | pro | forest | 150 |
| arrow | elf | NULL | NULL | 1000 |
| arrow | elf | basic | desert | 150 |
| arrow | elf | pro | desert | 50 |
| arrow | elf | pro | forest | 2000 |
// Using these - compile to nested array (i.e. you only need to maintain the datasources, not the array)
$items = ... // results from `item` datasource;
$races = ... // results from `race` datasource;
$tiers = ... // results from `tier` datasource;
$areas = ... // results from `area` datasource;
$nested_array = [];
foreach($items as $item){
$limit_data = ["_base" => $item["limit"]];
// populate races
$limit_data["race"] = [];
foreach($races as $race){
$race_data = ["tier" => []];
// populate tiers
foreach($tiers as $tier){
$tier_data = ["area" => []];
foreach($areas as $area){
$tier_data["area"][$area["area_id"]] = [];
}
$race_data["tier"][$tier["tier_id"]] = $tier_data;
}
$limit_data["race"][$race["race_id"]] = $race_data;
}
$item_limits = ... // results from `item_limit` datasource filtered by `item_id`
foreach($item_limits as $item_limit){
// expects "less specific" columns to always be set
// i.e. if `area` is set, `tier` and `race` should be too
// assigning variable by reference to keep this example short
$parent =& $limit_data["race"][$item_limit["race_id"]];
if(!isset($item_limit["tier_id"])){
$parent["_base"] = $item_limit["limit"];
continue;
}
$parent =& $parent["tier"][$item_limit["tier_id"]];
if(!isset($item_limit["area_id"])){
$parent["_base"] = $item_limit["limit"];
continue;
}
$parent["area"][$item_limit["area_id"]] = $item_limit["limit"];
}
$nested_array[$item["item_id"]] = ["limit" => $limit_data];
}
Memory Considerations
The above code shows how you could implement a system like this. However, in a live environment with many items, it would be better to only initialise/compile the nested/serialized array for a specific item as needed. Caching is your friend here.
Alternatively you can take this same approach and implement it in such a way that it only needs to query the datasource to reduce the memory footprint.
There are two questions actually.
How to build the character hierarchy with design pattern
How to rule the market with validation
This is my modeling suggestion
To the first problems. There are different properties to define a Character. Race and Tier. I am not sure if Area is the location of the character position. Or it is the biome of the character. If latter, then the character properties become three. I suggest to model the hierarchy with composition over inheritance. Otherwise, using traditional inheritance would result in many combination of classes (default Orc, Basic Orc, Pro Orc etc). Not to mention if more Race or Tier to come in the future.
To the second problem, I would not recommend chain of responsibility. Because with CoR, you need to define a long chain. Each processing object handle a variation of Character. You will need many processing object similar to the first problem.
I suggest to have a data structure registered what kind of Character could trade how many items. In my suggestion this is the responsibility of MarketAuthority. Imagine it has a map-like structure inside, and each entry it has a record call MarketRegulation. MarketRegulation define what kind of Character can buy or sell how many items. When trade happens, pass the character to MarketAuthority and find which MarketRegulation match the character. From the MarketRegulation result you know how many the character can trade.
Below is the example of MarketAuthority implementation.
class MarketAuthority
{
private $regulations;
function __construct()
{
$this->regulations = array();
// setting up regulations. Ideally they should be come from data source
// orc
$orc = new Character(null, null, new Orc());
array_push($this->regulations, new MarketRegulation($orc, new ActualLimit(50), TradeType::BUY));
.
.
.
// basic orc
$basicOrc = new Character(new Basic(), null, new Orc());
array_push($this->regulations, new MarketRegulation($basicOrc, new ActualLimit(50), TradeType::BUY));
$proForestOrc = new Character(new Pro(), new Forest(), new Orc());
array_push($this->regulations, new MarketRegulation($proForestOrc, new ActualLimit(150), TradeType::BUY));
// more to be set ...
}
public function buyCheck(Character $character, int $quantity): bool
{
$regulation = $this->getRegulation($character, TradeType::BUY);
return $regulation->getLimit()->allow($character, $quantity);
}
public function sellCheck(Character $character, int $quantity): bool
{
$regulation = $this->getRegulation($character, TradeType::SELL);
return $regulation->getLimit()->allow($character, $quantity);
}
public function buy(Character $character, int $quantity)
{
if ($this->buyCheck($character, $quantity)) {
$arrow = $character->getArrow() + $quantity;
$character->setArrow($arrow);
}
}
public function sell(Character $character, int $quantity)
{
if ($this->sellCheck($character, $quantity)) {
$arrow = $character->getArrow();
$character->setArrow($arrow - $quantity);
}
}
public function getRegulation(Character $character, TradeType $tradeType): MarketRegulation
{
$regulation = array_filter($this->regulations, function (MarketRegulation $r) use ($character, $tradeType) {
return $r->getCharacterConfig()->equals($character) && $r->getTradeType() == $tradeType;
});
return array_pop($regulation);
}
}
For a runnable prototype, please visit https://github.com/stackoverflow-helpdesk/free-market. Below is the prototype console output, simulating how the MarketAuthority regulate trades.
Basic Desert Elf [0] can buy up to 150 arrow
Basic Desert Elf [0] buy arrow*150
Basic Desert Elf [150]
Basic Desert Elf [150] only sell up to 50%. i.e.75
Basic Desert Elf [150] sell arrow*80
Basic Desert Elf [150]
Basic Desert Elf [150] cannot sell arrow*80
Orc [0] can buy up to 50 arrow
Orc [0] buy arrow*80
Orc [0]
Orc [0] cannot buy arrow*80
Consider the following scenario for API testing
Given I am using the API Service
When I send the <request> as <method> to <endpoint> endpoint with <key> having value <value>
Then The response status code is 200
Examples:
| request | method | endpoint | key | value |
| "All Keys" | "POST" | "endpointName" | "numericField" | 15 |
| "All Keys" | "POST" | "endpointName" | "numericField" | 15.12345 |
The above example creates a request with the specified parameters.
My problem is that while the integer (15) value is passed to the function accordingly, the float (15.12345) is converted into a string ("15.12345"). This happens straight as the function is called; it is not modified later on during another step.
Is there a way to keep the float value from turning into a string?
As requested, the send request step method is:
$data = $this->fulfilmentOptions->getDataValue($request);
$uri = $this->getMinkParameter('base_url') . $this->setEndpoint($endpoint);
array_walk_recursive($data, function(&$item, $originalKey) use ($key, $value) {
if ($originalKey === $key) {
$item = $value;
}
});
try {
$this->response = $this->client->request($method, $uri, [
'headers' => $this->fulfilmentOptions->getDataValue('CreateOrder API Headers'),
'body' => json_encode($data)
]);
} catch (\GuzzleHttp\Exception\RequestException $e) {
$this->response = $e->getResponse();
}
$this->responseContent = $this->response->getBody()->getContents();
One way of fixing the issue is to use floatval method for 'value' key to make sure you get the right type.
while playing with PHPExcel I came across some questions how properly handle validation/and inserting values into a database. I do not need any codes, just the general concept how to do it.
Firstly I iterate through first row to check if the columns are matching the given one ( if it fits the schema ).
On the next step, I get the rows and meanwhile its beeing validated row/column wise. If the type doesn't match I will get an error.
While validating the row, I need to get the Worker name and convert it to id get_worker_id().
Question number #1.
Is such solution a good practice? It will produce upto 100 queries. Foreach row - 1.
Question number #2
I also need to validate the rows once again, I would take the worker_id, the F and G column to check if such record isn't present in the database. I would simply introduce a function similar to get_worker_id() but it would return true/false if entry exists.
But again is this the proper way of doing it? By raw calculations my method would produce 100 selects ( get_worker_id ), 100 selects ( validate if exists ), 100 insert ( if all is ok ).
Im not sure if I am doing it properly. Could you hit me up with some advices?
Thanks in forwards.
Model for handling the xlsx file.
class Gratyfikant_model extends CI_Model {
private $_limit = 100;
const columns = array(
'A' => "Z",
'B' => "KS",
'C' => "G",
'D' => "S",
'E' => "Numer",
'F' => "Miesiąc", // required
'G' => "Data wypłaty", // required
'H' => "Pracownik", // required
'I' => "Brutto duże", // required
'J' => "ZUS pracownik", // required
'K' => "ZUS pracodawca", // required
'L' => "Do wypłaty", // required
'M' => "Obciążenie", // required
'N' => "FW");
const validators = array(
'F' => 'date',
'G' => 'date',
'H' => 'string',
'I' => 'float',
'J' => 'float',
'K' => 'float',
'L' => 'float',
'M' => 'float',
);
const validators_errors = array(
'float' => "Wartość nie jest liczbą",
'string' => "Wartość nie jest poprawna",
'date' => "Wartość nie jest datą"
);
protected $_required = array(
'H', 'I', 'J', 'K', 'L', 'M'
);
private $_sheet = array();
private $_sheet_pracownicy = array();
private $_agregacja = array();
protected $_invalid_rows = array();
public function __construct() {
parent::__construct();
}
public function read_data(array $dane) {
if (count($dane) > $this->_limit) {
throw new Exception('Limit wierszy to ' . $this->_limit);
}
$this->_sheet = $dane;
return $this;
}
public function column_validation() {
foreach ($this->_required as $r) {
if (!isset($this->_sheet[1][$r]) || $this->_sheet[1][$r] != self::columns[$r] || !array_key_exists($r, $this->_sheet[1])
) {
throw new Exception('Kolumna - ' . $r . ' - Wartość nagłówka nie pasuje do szablonu, powinno być ' . self::columns[$r]);
}
}
return $this;
}
function validateDate($date) {
$d = DateTime::createFromFormat('Y-m-d', $date);
return $d && $d->format('Y-m-d') === $date;
}
private function row_validation($k, $a, $v, $f) {
switch ($v) {
case "date":
$cellval = $this->validateDate(PHPExcel_Style_NumberFormat::toFormattedString($f, PHPExcel_Style_NumberFormat::FORMAT_DATE_YMD));
break;
case "float":
$cellval = is_float($f);
break;
case "string":
$cellval = is_string($f);
break;
default:
break;
}
if (!$cellval) {
$this->_invalid_rows[$a][$k] = $v;
}
}
public function get_sheet_data() {
$dane = $this->_sheet;
unset($dane[1]); // remove first col
$zus_pracownik = 0;
$zus_pracodawca = 0;
$zus_lacznie = 0;
$do_wyplaty = 0;
$obciazenie = 0;
$brutto = 0;
foreach ($dane as $a => $d) {
foreach (self::validators as $k => $v) {
echo $this->row_validation($k, $a, $v, $d[$k]);
}
if (!is_null($d["H"]) && !empty($d["H"])) {
// $this->_sheet_pracownicy[$d["H"]]["numer"] = PHPExcel_Style_NumberFormat::toFormattedString($d["E"], PHPExcel_Style_NumberFormat::FORMAT_DATE_DDMMYYYY);
$this->_sheet_pracownicy[] = array(
"pracownik" => $d["H"],
"miesiac" => PHPExcel_Style_NumberFormat::toFormattedString($d["F"], PHPExcel_Style_NumberFormat::FORMAT_DATE_YMD),
"data_wyplaty" => PHPExcel_Style_NumberFormat::toFormattedString($d["G"], PHPExcel_Style_NumberFormat::FORMAT_DATE_YMD),
"zus_pracownik" => $d["J"],
"zus_pracodawca" => $d["K"],
"zus_lacznie" => bcadd($d["K"], $d["J"]),
"do_wyplaty" => $d["L"],
"obciazenie" => $d["M"],
"brutto" => $d["I"],
"id_prac" => $this->get_worker_id($d["H"]));
$zus_pracownik = bcadd($zus_pracownik, $d["J"]);
$zus_pracodawca = bcadd($zus_pracodawca, $d["K"]);
$zus_lacznie = bcadd($zus_lacznie, bcadd($d["K"], $d["J"]));
$do_wyplaty = bcadd($do_wyplaty, $d["L"]);
$obciazenie = bcadd($obciazenie, $d["M"]);
$brutto = bcadd($brutto, $d["I"]);
}
}
$this->_agregacja = array(
"zus_pracownik" => $zus_pracownik,
"zus_pracodawca" => $zus_pracodawca,
"zus_lacznie" => $zus_lacznie,
"do_wyplaty" => $do_wyplaty,
"obciazenie" => $obciazenie,
"brutto" => $brutto
);
return $this;
}
public function display_result() {
if (empty($this->_invalid_rows)) {
return array(
"wartosci" => $this->_sheet_pracownicy,
"agregacja" => $this->_agregacja
);
}
}
public function display_errors() {
foreach ($this->_invalid_rows as $k => $a) {
foreach ($a as $key => $value) {
throw new Exception('Pole ' . $key . '' . $k . ' ' . self::validators_errors[$value]);
}
}
return $this;
}
public function get_worker_id($getAd) {
$this->db->select('id_pracownika as id')
->from('pracownicy')
->like('CONCAT( imie, \' \', nazwisko )', $getAd)
->or_like('CONCAT( nazwisko, \' \', imie )', $getAd);
$query = $this->db->get();
$result = $query->result_array();
if (isset($result[0]["id"])) {
return $result[0]["id"];
} else {
throw new Exception('Nie odnaleziono ' . $getAd . ' w bazie danych, proszę dodać pracownika a następnie ponownie wczytać plik');
}
}
}
Display
try {
$data['s'] = $this->gm
->read_data($sheetData)
->column_validation()
->get_sheet_data()
->display_errors()
->display_result();
} catch (Exception $e) {
$data['ex'] = $e->getMessage();
}
XLSX file example
+---+---------------+---+---+------------+---------+--------------+-----------+-------------+---------------+----------------+------------+------------+--------+
| Z | KS | G | S | Numer | Miesiąc | Data wypłaty | Pracownik | Brutto duże | ZUS pracownik | ZUS pracodawca | Do wypłaty | Obciążenie | FW |
+---+---------------+---+---+------------+---------+--------------+-----------+-------------+---------------+----------------+------------+------------+--------+
| | nieprzekazany | G | | 03.08.2017 | sie.17 | 08.09.2017 | Worker1 | 2000 | 274,2 | 392,2 | 1459,48 | 2392,2 | (brak) |
| | nieprzekazany | G | | 03.08.2017 | sie.17 | 08.09.2017 | Worker2 | 1000 | 137,1 | 171,6 | 768,24 | 1171,6 | (brak) |
| | nieprzekazany | G | | 03.08.2017 | sie.17 | 08.09.2017 | Worker3 | 2000 | 274,2 | 392,2 | 1413,88 | 2392,2 | (brak) |
| | nieprzekazany | G | | 03.08.2017 | sie.17 | 08.09.2017 | Worker4 | 2000 | 274,2 | 392,2 | 1418,88 | 2392,2 | (brak) |
+---+---------------+---+---+------------+---------+--------------+-----------+-------------+---------------+----------------+------------+------------+--------+
This really depends on the scale of your application and how frequently this Excel file will be imported. For example, if your application receives little to no traffic then running several queries per line is not the end of the world. If you already have the server and database setup and running then you might as well make use of them. Conversely, if your application is under constant heavy load then trying to minimize the amount of queries you run may be a good idea.
Option 1
If your application is small and/or doesn't get much traffic then don't worry about the ~300 queries you need to make. MySQL is not fragile and if you have indexed your data well your queries will be very fast.
Option 2
Move to querying the data you need first and storing it in memory so you can perform your logic checks in PHP.
This means for Question 1 you should get all of your workers in one query and then build a lookup array in PHP.
Here is a very rough example:
// Get all workers
SELECT worker_name, worker_id FROM workers;
// Build a lookup array from the query results
$worker_array = array(
'Worker1' => 1,
'Worker2' => 2,
...
);
// Then as you loop each row check if the work is in your lookup array
if ( ! isset($worker_array[$excel_row['worker_name']])) {
// do something
}
Likewise for Question 2 you could get your unique data samples in one query (you don't need the entire record, just the unique fields). However, this may present a problem if you have a lot of unique data samples.
Option 3
Create a temporary table in MySQL and import your Excel data without performing any logic checks. Then you can perform your logic checks entirely in SQL.
Here is a very rough example without knowing anything about your data structure:
-- Get all records in the Excel data that match unique data samples
SELECT
*
FROM
temporary_table tt
JOIN
workers w
ON w.worker_name=tt.worker_name
JOIN
data d
ON d.worker_id=w.worker_id
AND d.col_f=tt.col_f
AND d.col_g=tt.col_g
If there are no issues with the data then you can perform an INSERT from your temporary table into your data table. This limits your queries to the initial insert (you can batch this for better performance as well), the data check and the insert from temp to real data.
Recap
It all comes down to your application. If you can get away with doing Option 1 and you've already got it implemented then that's fine for now. You don't need to over optimize things if you don't see this application growing like crazy.
However, if you are worried about scale and growth then I'd personally look at implementing Option 3.
There are multiple concerns here:
Split import into stages.
Validate headers. (Break importing if errors found) 2) Iterate
over each row.
Validate row.
Import if valid.
Log error if any.
Stop processing file if all rows where processed or go back to 2.
As to weather you need some chunking it depend on how much time and memory your script is consuming. If you need it, it's as simple as reading X rows to memory and then processing it. At extreme you can load each record separately.
If you do not need it just load it all to array.
chunking - consuming up to X rows in a single iteration, then clearing memory then consuming next chunk...
100 queries just doesn't sound right to me for a single php instance.
https://secure.phabricator.com/book/phabcontrib/article/n_plus_one/
Or just search for n plus 1 query problem
I have a json object in my php script that was encoded using the json_encode php function.
Here is the object when var_dumped...
string '{"voting_sys":"50","beta_site":"50"}' (length=36)
string '{"voting_sys":"50","beta_site":"50"}' (length=36)
Database structure:
My goal is to get the sum of the values in the voting_sys for each user, and in the beta_site...this is going to be used for voting, but on an unknown amount of features/values.
Any ideas? I have tried the following...
$voters = DB::table('votes')->get();
foreach($voters as $vote){
$vote_array[$voter->user_id]=json_decode($voter->value, true);
}
var_dump($vote_array);
This returns the decoded json object to the array.
I would assign the "voting_sys" as the key for the array, and then the integer value to the value of the array, but there will be an unknown number of features. In this example, there are only two features the users can vote on, but there may be more at a later date. I use the feature ID to roll out a new set of features the users can vote on.
I am using Laravel 4.1
[Edit: Result]
$feature_list = DB::table('features')->where('rev_id', Config::get('app.beta_rev'))->get();
$feature_array=array();
foreach ($feature_list as $feature){
array_push($feature_array, $feature->name);
}
foreach($feature_array as $feature){
$voters = DB::table('votes')
->select(DB::raw('sum(value)'))
->where('feature_name', '=', $feature)
->get();
echo $feature.' - ';
var_dump($voters);
echo '<br />';
}
which when called, dumps:
voting_sys -
array (size=1)
0 =>
object(stdClass)[248]
public 'sum(value)' => string '149' (length=3)
beta_site -
array (size=1)
0 =>
object(stdClass)[249]
public 'sum(value)' => string '69' (length=2)
Which is exactly correct for the votes I entered. Thanks for the help.
I would suggest using a slightly different database structure. It is almost never a good idea to serialize / json_encode data in your database. Since you already have a dedicated table for votes it should be simple to change your table from what you curretly have to the following:
id | user_id | feature | value
------------------------------
1 | 2 | sys | 50
2 | 2 | beta | 40
3 | 3 | sys | 50
This would make counting very trivial:
SELECT SUM(value) FROM table WHERE feature = 'sys'
Use array_sum
array_sum — Calculate the sum of values in an array
$voters = DB::table('votes')->get(); // get the JSON response response
$jsonDecodedArray = json_decode($voters,true); // decode the JSON
$sum = array_sum($jsonDecodedArray); // Use php array_sum
I have two very similar classes. Lets say Class A and Class B.
+---------------+ +---------------+
| Class A | | Class B |
|---------------| |---------------|
| Name | | Name |
| ZIP | | ZIP |
| TelPhone | | TelPhone |
| | | MobilePhone |
+---------------+ +---------------+
I want to compare them in the values for all common attributes.
Here's a way I tried it, but doing it for all attributes (got more than only 3 attributes) looks like a overkill for me:
$differences = array();
if($classA->getName() != $classB->getName()) {
array_push(
$differences,
array('name' => array(
'classA' => $classA->getName(),
'classB' => $classB->getName()
)
));
}
// and the same code for every attribute....
What's the best approach here?
Additional to the handiwork, it is also not automatically updated if the classes are getting altered. For example if Class A gets also a MobilePhone attribute.
Please don't tell me, that I should do some Polymorphism, it's just an example to clarify.
I'm interested in the difference, so not only the attributes, also the values itself inside the attributes.
thanks
It's not the sexiest thing (because of the substring to getters.., but I can't go with properties, I think sym, but I got it:
// getting an array with all getter methods of a class
private function getGettersOf($object) {
$methodArray = array();
$reflection = new ReflectionClass($object);
$methods = $reflection->getMethods();
foreach ($methods as $method) {
// nur getter
if(strtolower(substr($method->getName(), 0, 3)) == "get") {
array_push($methodArray, $method->getName());
}
}
return $methodArray;
}
// getting an array with all differences
public function getDifferences($classA, $classB) {
// get list of attributes (getter methods) in commond
$classAMethods = $this->getGettersOf($classA);
$classBMethods = $this->getGettersOf($classB);
$intersection = array_intersect($classAMethods, $classBMethods);
$differences = array();
// iterate over all methods and check for the values of the reflected methods
foreach($intersection as $method) {
$refMethodClassB = new ReflectionMethod($classB, $method);
$refMethodClassA = new ReflectionMethod($classA, $method);
if($refMethodClassB->invoke($classB) != $refMethodClassA->invoke($classA)) {
array_push(
$differences,
array($method => array(
'classA' => $refMethodClassA->invoke($classA),
'classB' => $refMethodClassB->invoke($classB)
)
));
}
}
return $differences;
}
Special thanks to George Marques's comment.