I have 2 questions
1.) how to write update_defile($array_value){...} function?
define_file.php
<?php
define("FIST_NAME", "something1");
define("LAST_NAME", "something2");
define("ADDRESS", "something3");
?>
"something" is not a constant value that can be change every method Call(update_defile($array_value)
value set
$array_value = ("FIST_NAMe" => "duleep", "LAST_NAME" => "dissnayaka", "AGE" => "28" );
after call method(update_defile($array_value){.....}) "define_file.php"
file want to be look like bellow
<?php
define("FIST_NAME", "duleep");
define("LAST_NAME", "dissnayaka");
define("ADDRESS", "something3");
define("AGE", "28");
?>
2).
My datbase is Oracle. I already saved configuration value in the data base but frequently use these configuration value for my application. So i get value form database and save in the define_file.php as increase performance(down rate database call) but I'm not sure i can increase performance keep configuration value in the PHP file please explain. what is the best way increase performance my application and other alternative solutions welcome.
Why cant u use session to store such values , then u can access and modify from anywhere
in the script.
<?php
session_start();
$_SESSION["FIST_NAME"]= "something1";
$_SESSION["LAST_NAME"]= "something2";
$_SESSION["ADDRESS"]= "something3";
?>
public function update($form_config_arr)
{
if( (is_readable($config_file_path)) && is_writable($config_file_path))
{
if(!$config_old_file_content = file_get_contents($config_file_path))
{
throw new Exception('Unable to open file!');
}
$i = 0;
$config_old_arr = array();
$config_new_arr = array();
foreach ($form_config_arr as $constant => $value){
$config_old_line = $this->getLine($constant);
$config_old_arr[$i] = $config_old_line;
if(($value == 'true') || ($value == 'false')){
$config_new_arr[$i] = "define ( '$constant', $value );\n";
}else{
$config_new_arr[$i] = "define ( '$constant', '$value' );\n";
}
$i++;
}
$config_new_file_content = str_replace($config_old_arr, $config_new_arr, $config_old_file_content);
$new_content_file_write = file_put_contents($config_file_path, $config_new_file_content);
foreach ($config_new_arr as $constant => $value)
{
echo $value.'<br/>';
}
return true;
}else{
throw new Exception('Access denied for '.$config_file_path);
return false;
}
}
/**
*
* #param string $constant
* #return string
*/
private function getLine($constant)
{
$match_line = '';
$config_file = fopen($config_file_path, "r");
if($config_file)
{
//Output a line of the file until the end is reached
$i = 0;
while(!feof($config_file))
{
$i++;
$config_old_line = fgets($config_file);
$pos = strpos($config_old_line, $constant);
if( $pos !== false )
{
$match_line= $config_old_line;
}
}
fclose($config_file);
return $match_line;
}else{
throw new Exception('Unable to open file!');
}
}
What you are trying to do is edit a file.
Simply create another php script: updater.php
It should poll the database, fetch the values and update the values in define_file.php
Look for php file handling functions here: http://www.w3schools.com/php/php_file.asp
Related
I am trying to detect status of invoice from a json file, then if the status is a confirmed payment, update the status and write the json to a new location, then unlink the existing json location.
<?php
// get posted variables or die;
if (isset($_POST['num'])) {
$invoice = strip_tags($_POST['num']);
$filename = $invoice.'.json';
} else {
die;
}
if (isset($_POST['status'])) {
$status = strip_tags($_POST['status']);
} else {
die;
}
// get existing invoice
$content = file_get_contents('data/'.$invoice.'.json');
$data = json_decode($content, true);
// read json into variables
$email = $data['email'];
$id = $data['id'];
$addr = $data['tac_address'];
$os = $data['os'];
$exp = $data['experience'];
$hosting = $data['type'];
if (isset($data['telegram']) && $data['telegram'] != '') { $telegram = $data['telegram']; } else { $telegram = ''; }
if (isset($data['linkedin']) && $data['linkedin'] != '') { $linkedin = $data['linkedin']; } else { $linkedin = ''; }
if (isset($data['pay_status']) && $data['pay_status'] != '' && $data['pay_status'] == $status) { $status = $data['pay_status']; }
$payment_addr = $data['bitcoin'];
$payment_value = $data['value'];
$payment = substr($payment_value, 0, -4);
// turn variables into json array
$arr = array(
'id' => $invoice,
'email' => $email,
'tac_address' => $addr,
'os' => $os,
'experience' => $exp,
'type' => $hosting,
'telegram' => $telegram,
'linkedin' => $linkedin,
'bitcoin' => $payment_addr,
'value' => $payment_value,
'pay_status' => $status
);
$json = json_encode($arr);
// check status if paid save output to new location and delete old file
if ($status == 'Confirmed Payment') {
file_put_contents('paid_data/'.$filename, $json);
unlink('data/'.$filename);
}
The problem I am facing is that file_put_contents('paid_data/'.$filename, $json); ends up a file with a bunch of NULL variables. If I remove the unlink the variables save just fine, when I add it back the variables are all NULL.
So how can I verify file_put_contents takes place before the unlinking happens?
Also.... WHY does this happen? Isn't php supposed to be linear and shouldn't file_put_contents finish before the next line is carried out? Everything I have read about file_put_contents suggests as much. So why does the unlink take place before writing the content to a new location?
I still hope for a better answer, but so far this is my working solution to the problem. I changed the final if statement to the following. This seems to solve the issue - but there really has to be a better way than this. This feels very "hacky".
if ($status == 'Confirmed Payment') {
file_put_contents('paid_data/'.$filename, $json);
$i = 0;
while ($i < 1000) {
$i++;
if (file_exists('paid_data/'.$filename)) {
unlink('data/'.$filename);
break;
}
}
}
After mimicking your file structure and seeding a few examples, I was able to execute your code as is with the expected results. However, file_put_contents willreturn false on failure, so you might try something like this:
if ($status == 'Confirmed Payment') {
if(!file_put_contents('paid_data/'.$filename, $json);){
print_r(error_get_last());
die;
}
unlink('data/'.$filename);
}
Your code as originally written should be fine, as far as I can see. Usually when I see the kind of behavior you're describing, the problem is that the script itself is being called twice (or more) and overlapping calls are manipulating the same file.
I would definitely put in some debugging statements to verify this; I don't know your environment, but a simple line written to a log will probably be enlightening.
just developed a simple CLI php code that calculates the multiplication table of your choosen size but when I check the files to make sure they stick to PSR coding standards, it gives me four errors/violations. I don't know where in the files the errors are after several attempts and days of work on the files.
there are two files:
cliVersion.php and generateCLITable.php
The first file gives me 1 PSR error and the second one gives me 3 PSR errors.
this is how I generate the multiplication table of size 12 on command line :
php cliVersion.php 12
can anyone help me to find out the PSR errors in the files.
here's the files and the error report:
cliVersion.php
<?php
declare(strict_types=1);
require_once 'generateCLITable.php';
require_once '../model/validateInput.php';
?>
<?php
// Assign the user's input argument value to $input variable
$inputString = $argv[1];
$errorMessage = "Please enter a valid argument (a whole number greater than 1)";
// Check if the user's input argument is not null or empty
if ($inputString == null || $inputString == "") {
echo $errorMessage;
} else {
// Create an object of ValidateInput Class
$inputData = new ValidateInput();
/*
Validate the $input variable received from the user as an argument.
The code will be safe to be processed after this line.
*/
$validatedInput = $inputData->validateInputData($inputString);
$validatedInputInt = (int)$validatedInput;
/*
Check if the validated input is an Integer and if it is,
generates the table else returns the error message
*/
$isInputValidInt = $inputData->isInputInt($validatedInputInt);
if ($isInputValidInt && $validatedInputInt > 1) {
$multTable = new MultTable();
$multTable->generateTable($validatedInputInt);
} else {
echo $errorMessage;
}
}
echo PHP_EOL;
GenerateCLITable.php
<?php
declare(strict_types=1);
class MultTable
{
/**
* The public generateTable function generates the multiplication table
*
* #param int $inputValue
*
* #return void
*/
public function generateTable(int $inputValue)
{
// Create first row of table headers - green colour
for ($col=1; $col <= $inputValue; $col++) {
echo "\033[35m \t$col \033[0m";
}
// Create remaining rows
for ($row=1, $col=1; $row <= $inputValue; $row++) {
echo "\n";
// First cell is a table header - green colour
if ($col == 1) {
echo "\033[35m \n$row \033[0m";
}
while ($col <= $inputValue) {
echo "\t" . $row * $col++ ;
}
// Reset $col at the end of the row
$col = 1;
}
}
}
Error report:
cliVersion.php
----------------------------------------------------------------------
FOUND 1 ERROR AFFECTING 1 LINE
generateCLITable.php
----------------------------------------------------------------------
FOUND 3 ERRORS AFFECTING 3 LINES
I strongly recommend to use https://github.com/FriendsOfPHP/PHP-CS-Fixer in such cases.
I guess you are trying to unit test the code. I would probably focus on trying to be as thoughtful with the code first . Take cliVersion, I think you can simplify it greatly by creating a single method to handle the input. Also I find a lot of issue with your comments and variables and overdesign.
Revised Version:
<?php
//declare(strict_types=1); // I'm using php 5 so I don't have this (but ok for you)
require_once 'generateCLITable.php';
require_once '../model/validateInput.php';
$must_be_gtr_than = 1; // set floor val for validation
$inputData = new ValidateInput($must_be_gtr_than);
$multTable = new MultTable();
if ($inputData->isValidIntegerData($argv[1])) {
$tableSize = (int) $argv[1];
$multTable->generateTable($tableSize);
} else {
echo "Error: Please enter a valid argument (a whole number greater than ".$must_be_gtr_than.")";
die();
}
In this example I have one method alone that validates that I have an integer > 0, if isValidIntegerData than proceed . Think about ease of code and names that make sense generateTable doesn't tell me much, is there a better name ? Things like that. Take "$validatedInputInt", that doesn't speak to what you are doing as well as what that int is, "tableSize" makes more sense to me. Also we many times save camel back for Classes etc.. I would look up PSR2.
For example we use
CONST_SOMETHING = xx; //constants
var_x or varx // lowercase for vars
methodX //camel back
ClassName // ucwords for classes
etc..
UPDATE:
This is how I would probably go about building something like this:
<?php
//declare(strict_types=1); // PHP5.x Example
class GenerateCLITable
{
const DEFAULT_BOARD_SIZE = 12;
public $game_board, $table_size;
public function __construct($input = self::DEFAULT_BOARD_SIZE)
{
$this->game_board = $this->generateTable($input);
}
public function generateTable($inputValue = self::DEFAULT_BOARD_SIZE)
{
$table = "";
// Create first row of table headers - green colour
for ($col=1; $col <= $inputValue; $col++) {
$table .= "\033[35m \t$col \033[0m";
}
// Create remaining rows
for ($row=1, $col=1; $row <= $inputValue; $row++) {
$table .= "\n";
// First cell is a table header - green colour
if ($col == 1) {
$table .= "\033[35m \n$row \033[0m";
}
while ($col <= $inputValue) {
$table .= "\t" . $row * $col++ ;
}
// Reset $col at the end of the row
$col = 1;
}
$this->game_board = $table;
$this->table_size = $inputValue;
return $table;
}
public function isValidInputValue($input = '', $size = 0)
{
return (!empty($input) && $input > $size) ? (is_int((int) $input)) : false;
}
}
//require_once 'generateCLITable.php';
$multTable = new GenerateCLITable();
$must_be_gtr_than = 1;
if (!$multTable->isValidInputValue($argv[1], $must_be_gtr_than)) {
echo "Error: Please enter a valid argument (a whole number greater than ".$must_be_gtr_than.")";
die();
}
$table = $multTable->generateTable((int) $argv[1]);
echo $table . "\n";
I have a script that imports records to multiple database tables, all relation to one parent entity (address).
If the address already exist, extra columns should just be updated according to the csv. The same counts for all other entities. A counter ($exist++) should increase or an array ($existingRecords) should be filled with already existing records.
If mandatory fields are empty in the record, that record should be added to another array ($failedRecords) or another counter ($failed++) should increase.
If the address doesn't yet exist and should be created with all fields just a counter ($successful++) should increase.
In the end I have an array $result that give the number of failed, successful, and already existing (but updated) records, for user feedback.
How can I implement this in a nice clean manner without messing my current script too much up? Because what is happening right now, if a record already exist the $exist counter increase but the $successful counter as well, and I only want the $exist counter to increase if a record already already exists, and only the $successful counter should increase if a record still has to be added and was added successfully. Same goes for the $failed counter.
Here is my script (with what I tried):
public function import(CsvFile $csv) {
$root = __DIR__.'/../../../../../';
$file = $root.'var/data/'.$csv->getCsvName();
$fp = fopen($file, "r");
$batchSize = 25;
$header = null;
$successful = 0;
$failed = 0;
$exist = 0;
$results = [];
while ($row = fgetcsv($fp, null, ";")) {
if ($header === null) {
$header = $row;
continue;
}
$record = array_combine($header, $row);
// cast all values to correct data types
foreach ($record as $key => &$value) {
if (strpos($key, 'datum') !== false ||
strpos($key, 'tijdstip') !== false &&
strlen($value) == 8 &&
is_numeric($value)
) {
$value = \DateTime::createFromFormat('Ymd', $value);
}
if ($value === "") {
$value = null;
}
if (is_numeric($value)) {
intval($value) == $value ? $value = (int)$value : $value = (float)$value;
}
}
// required fields
if (!$record['name'] ||
!$record['surname'] ||
!$record['email'] ||
!$record['phone'] ||
!$record['street'] ||
!$record['houseNo'] ||
!$record['town'] ||
!$record['postcode'] ||
!$record['location'] ||
!$record['lecture'] ||
!$record['session'] ||
) {
$failed++;
continue;
}
$student = $this->em->getRepository(Student::class)->findStudent(
$record['name'], $record['surname'],
$record['email'], $record['phone']
);
if (!$student) {
$student = new Student();
$student->setName($record['name']);
$student->setSurname($record['surname']);
$student->setEmail($record['email']);
$student->setPhone($record['phone']);
} else {
$exist++;
}
$student->setAge($record['age']);
$student->setLength($record['length']);
$address = $this->em->getRepository(Address::class)->findOneBy([
'street' => $record['street'],
'houseNo' => $record['houseNo'],
'town' => $record['town'],
'postcode' => $record['postcode'],
);
if (!$address) {
$address = new Address();
$address->setStreet($record['street']);
$address->setHouseNo($record['houseNo']);
$address->setPostcode($record['postcode']);
$address->setTown($record['town']);
}
$student->setAddress($address);
$lecture = $this->em->getRepository(Lecture::class)->findOneBy([
'location' => $record['location'],
'lecture' => $record['lecture'],
'session' => $record['session'],
]);
if (!$lecture) {
$lecture = new Lecture();
$lecture->setLocation($record['location']);
$lecture->setLecture($record['lecture']);
$lecture->setSession($record['session']);
}
$lecture->setTime($record['time']);
$lecture->setSubject($record['subject']);
$student->setLecture($lecture);
$validationErrors = $this->validator->validate($student);
if (!count($validationErrors)) {
$this->em->persist($student);
$successful++;
}
if (($successful % $batchSize) == 0) {
$this->em->flush();
}
}
fclose($fp);
$csv->setImported(true);
$this->em->persist($csv);
$this->em->flush(); // Also persist objects that did not make up an entire batch
$results['successful'] = $successful;
$results['failed'] = $failed;
$results['exist'] = $exist;
return $results;
}
You can replace the existing records counter with a flag that is set to TRUE only if the current record is an existing one, and use it at the end before persisting the record.
You can set the flag to FALSE on the beginning of each loop:
while ($row = fgetcsv($fp, null, ";")) {
$existingRecordFlag = FALSE; // initialize the flag for the current record
then update it instead of the counter :
if (!$student) {
$student = new Student();
$student->setName($record['name']);
$student->setSurname($record['surname']);
$student->setEmail($record['email']);
$student->setPhone($record['phone']);
} else {
$existingRecordFlag = TRUE; //update the flag
}
then before persisting user check the value for the flag and according to it update the counter:
$validationErrors = $this->validator->validate($student);
if (!count($validationErrors)) {
$this->em->persist($student);
if ( !$existingRecordFlag){
$successful++; //new record
}else{
$exist++; //existing user
}
}else{
$failed++; //failed as the validations has errors
continue;
}
also you can add the existing records to the batch counter as they might be updated, they can also be persisted with the successful ones
if ((($successful+$exist) % $batchSize) == 0) {
$this->em->flush();
}
In your block handling the addresses you could an existing/failed counter quite easily:
$exist++;
if (!$address) {
$exist--;
$successful++;
//...
}
This will always increase the exist-counter, but jump back if address is empty and increase the new address-counter instead. Alternatively you could work with array_push($record) and array_pop($record) to add/remove the current record from a list. This might cause memory issues, since you keep your records in multiple arrays and you might run into out of memory errors.
For missing mandatory fields you'd have to do a check on the $address afterwards to see if it's not empty/containing invalid data and then increase the counter/update the field.
If you want
I already asked a question belonging this issue here
The code from the accepted answer by RiggsFolly works really proper but there is a small issue with that. I needed some days to test it out and searched for the reason why this is not the best way to solve the main goal. I was pleased to open a new question.
The code from RiggsFolly is based on $current_provider so the while-loop checks on every round if $current_provider has changed. So far so good. BUT now I needed to add a comprehensive logic. It meens that I added a true/false variable that simply checks if a value from an fetched object is equal to a certain string. This comparison is focused on a specific list item and not to the basic $current_provider.
So the goal is that $current_provider checks each fetched object for true/false and will be independent from $current_provider. At the moment I try to extend with a second loop but just want to give an example in the hope that it will be clear what to achieve:
$service = $db->query("SELECT * FROM `system` ORDER BY provider, artist");
$provider = NULL;
$close = false;
while ($data = $service->fetch_object()) {
$amount_1 = $data->digit_1; //db-structure: float
$amount_2 = $data->digit_2; //db-structure: float
if ($amount_1 == $amount_2) {
$close = true;
}
if ( $current_provider != $data->provider ) {
if ( $current_provider !== NULL ) {
echo '</div>close container in case of current_provider is already set';
}
echo '<div class="provider">open a new container in case of current_provider is not like data->provider or empty';
$current_provider = $data->provider;
}
echo 'some styling for each object';
if ($close === true ) {
echo '<div class="specific">if the amount_1 is same like amount_2 for a single object add only for this object a certain div';
} else {
echo '<div>show standard container even on specific object';
}
echo '</div><!--close container provider-->';
}
Kind regards.
I am still not sure I understand what you are actually trying to achieve here but maybe if you lay your decision making out like this it will all seem more obvious what you may need to do in addition to what I am suggesting.
The moving of
$amount_1 = $data->digit_1;
$amount_2 = $data->digit_2;
from a perfectly good object properties to 2 scalar variables is totally unnecessary why store everything twice, you will eventually run out of memory, but more importantly if you leave them in the object and test them using if ($data->digit_1 == $$data->digit_2) { its never confusing where this data came from!
Also testing the digits at the top of the loop only to set ANOTHER scalar variable to use later at the bottom of the loop is a waste of time. Those properties dont change between top and bottom of the loop so test the actual object where you want to make the decision and then put out the required HTML right there and then. Another potential confusion averted and 8 to 16 bytes of memory not wasted!
$service = $db->query("SELECT * FROM `system` ORDER BY provider, artist");
$current_provider = NULL;
while ($data = $service->fetch_object()) {
if ( $current_provider != $data->provider ) {
if ( $current_provider !== NULL ) {
echo '</div>close container in case of current_provider is already set';
}
echo '<div class="provider">open a new container in case of current_provider is not like data->provider or empty';
$current_provider = $data->provider;
}
echo 'some styling for each object';
// at this point we test the 2 digits and if equal
// add an extra bit of HTML to the output
if ($data->digit_1 == $data->digit_2) {
echo '<div class="specific">if the amount_1 same like amount_2 for a single object add only for this object an certain div';
} else {
echo '<div>show standard container even on specific object';
}
echo '</div>;
}
To avoid playing with opening and closing element better to store them in array and in the end output them.
Look at my example, it's simple:
$service = $db->query("SELECT * FROM `system` ORDER BY provider, artist");
$provider = NULL;
$lines = array();
while ($data = $service->fetch_object()) {
$close = false;
if ($something === $another) {
$close = true;
}
if ( $provider != $data->provider ) {
$lines[] = '<div class="provider">'.$data->provider.'</div>';
$provider = $data->provider;
}
if ($close === true ) {
$lines[] = '<div class="specific">add container for just a specific object when close === true within the while loop</div>';
} else {
$lines[] = '<div>show standard container on specific object</div>';
}
}
foreach($lines AS $line) {
echo $line;
}
I am working with SilverStripe, and I am working on making a newspage.
I use the DataObjectAsPage Module( http://www.ssbits.com/tutorials/2012/dataobject-as-pages-the-module/ ), I got it working when I use the admin to publish newsitems.
Now I want to use the DataObjectManager Module instead of the admin module to manage my news items. But this is where the problem exists. Everything works fine in draft mode, I can make a new newsitem and it shows up in draft. But when I want to publish a newsitem, it won't show up in the live or published mode.
I'm using the following tables:
-Dataobjectaspage table,
-Dataobjectaspage_live table,
-NewsArticle table,
-NewsArticle_Live table
The Articles have been inserted while publishing in the Dataobjectaspage table and in the NewsArticle table... But not in the _Live tables...
Seems the doPublish() function hasn't been used while 'Publishing'.
So I'm trying the use the following:
function onAfterWrite() {
parent::onAfterWrite();
DataObjectAsPage::doPublish();
}
But when I use this, it gets an error:
here is this picture
It seems to be in a loop....
I've got the NewsArticle.php file where I use this function:
function onAfterWrite() {
parent::onAfterWrite();
DataObjectAsPage::doPublish();
}
This function calls the DataObjectAsPage.php file and uses this code:
function doPublish() {
if (!$this->canPublish()) return false;
$original = Versioned::get_one_by_stage("DataObjectAsPage", "Live", "\"DataObjectAsPage\".\"ID\" = $this->ID");
if(!$original) $original = new DataObjectAsPage();
// Handle activities undertaken by decorators
$this->invokeWithExtensions('onBeforePublish', $original);
$this->Status = "Published";
//$this->PublishedByID = Member::currentUser()->ID;
$this->write();
$this->publish("Stage", "Live");
// Handle activities undertaken by decorators
$this->invokeWithExtensions('onAfterPublish', $original);
return true;
}
And then it goes to DataObject.php file and uses the write function ():
public function write($showDebug = false, $forceInsert = false, $forceWrite = false, $writeComponents = false) {
$firstWrite = false;
$this->brokenOnWrite = true;
$isNewRecord = false;
if(self::get_validation_enabled()) {
$valid = $this->validate();
if(!$valid->valid()) {
// Used by DODs to clean up after themselves, eg, Versioned
$this->extend('onAfterSkippedWrite');
throw new ValidationException($valid, "Validation error writing a $this->class object: " . $valid->message() . ". Object not written.", E_USER_WARNING);
return false;
}
}
$this->onBeforeWrite();
if($this->brokenOnWrite) {
user_error("$this->class has a broken onBeforeWrite() function. Make sure that you call parent::onBeforeWrite().", E_USER_ERROR);
}
// New record = everything has changed
if(($this->ID && is_numeric($this->ID)) && !$forceInsert) {
$dbCommand = 'update';
// Update the changed array with references to changed obj-fields
foreach($this->record as $k => $v) {
if(is_object($v) && method_exists($v, 'isChanged') && $v->isChanged()) {
$this->changed[$k] = true;
}
}
} else{
$dbCommand = 'insert';
$this->changed = array();
foreach($this->record as $k => $v) {
$this->changed[$k] = 2;
}
$firstWrite = true;
}
// No changes made
if($this->changed) {
foreach($this->getClassAncestry() as $ancestor) {
if(self::has_own_table($ancestor))
$ancestry[] = $ancestor;
}
// Look for some changes to make
if(!$forceInsert) unset($this->changed['ID']);
$hasChanges = false;
foreach($this->changed as $fieldName => $changed) {
if($changed) {
$hasChanges = true;
break;
}
}
if($hasChanges || $forceWrite || !$this->record['ID']) {
// New records have their insert into the base data table done first, so that they can pass the
// generated primary key on to the rest of the manipulation
$baseTable = $ancestry[0];
if((!isset($this->record['ID']) || !$this->record['ID']) && isset($ancestry[0])) {
DB::query("INSERT INTO \"{$baseTable}\" (\"Created\") VALUES (" . DB::getConn()->now() . ")");
$this->record['ID'] = DB::getGeneratedID($baseTable);
$this->changed['ID'] = 2;
$isNewRecord = true;
}
// Divvy up field saving into a number of database manipulations
$manipulation = array();
if(isset($ancestry) && is_array($ancestry)) {
foreach($ancestry as $idx => $class) {
$classSingleton = singleton($class);
foreach($this->record as $fieldName => $fieldValue) {
if(isset($this->changed[$fieldName]) && $this->changed[$fieldName] && $fieldType = $classSingleton->hasOwnTableDatabaseField($fieldName)) {
$fieldObj = $this->dbObject($fieldName);
if(!isset($manipulation[$class])) $manipulation[$class] = array();
// if database column doesn't correlate to a DBField instance...
if(!$fieldObj) {
$fieldObj = DBField::create('Varchar', $this->record[$fieldName], $fieldName);
}
// Both CompositeDBFields and regular fields need to be repopulated
$fieldObj->setValue($this->record[$fieldName], $this->record);
if($class != $baseTable || $fieldName!='ID')
$fieldObj->writeToManipulation($manipulation[$class]);
}
}
// Add the class name to the base object
if($idx == 0) {
$manipulation[$class]['fields']["LastEdited"] = "'".SS_Datetime::now()->Rfc2822()."'";
if($dbCommand == 'insert') {
$manipulation[$class]['fields']["Created"] = "'".SS_Datetime::now()->Rfc2822()."'";
//echo "<li>$this->class - " .get_class($this);
$manipulation[$class]['fields']["ClassName"] = "'$this->class'";
}
}
// In cases where there are no fields, this 'stub' will get picked up on
if(self::has_own_table($class)) {
$manipulation[$class]['command'] = $dbCommand;
$manipulation[$class]['id'] = $this->record['ID'];
} else {
unset($manipulation[$class]);
}
}
}
$this->extend('augmentWrite', $manipulation);
// New records have their insert into the base data table done first, so that they can pass the
// generated ID on to the rest of the manipulation
if(isset($isNewRecord) && $isNewRecord && isset($manipulation[$baseTable])) {
$manipulation[$baseTable]['command'] = 'update';
}
DB::manipulate($manipulation);
if(isset($isNewRecord) && $isNewRecord) {
DataObjectLog::addedObject($this);
} else {
DataObjectLog::changedObject($this);
}
$this->onAfterWrite();
$this->changed = null;
} elseif ( $showDebug ) {
echo "<b>Debug:</b> no changes for DataObject<br />";
// Used by DODs to clean up after themselves, eg, Versioned
$this->extend('onAfterSkippedWrite');
}
// Clears the cache for this object so get_one returns the correct object.
$this->flushCache();
if(!isset($this->record['Created'])) {
$this->record['Created'] = SS_Datetime::now()->Rfc2822();
}
$this->record['LastEdited'] = SS_Datetime::now()->Rfc2822();
} else {
// Used by DODs to clean up after themselves, eg, Versioned
$this->extend('onAfterSkippedWrite');
}
// Write ComponentSets as necessary
if($writeComponents) {
$this->writeComponents(true);
}
return $this->record['ID'];
}
Look at the $this->onAfterWrite();
It probably goes to my own function on NewsArticle.php and there starts the loop! I'm not sure though, so i could need some help!!
Does anyone knows how to use the doPublish() function?
The reason that is happening is that in the DataObjectAsPage::publish() method, it is calling ->write() - line 11 of your 3rd code sample.
So what happens is it calls ->write(), at the end of ->write() your onAfterWrite() method is called, which calls publish(), which calls write() again.
If you remove the onAfterWrite() function that you've added, it should work as expected.
The doPublish() method on DataObjectAsPage will take care of publishing from Stage to Live for you.