Klavyio woocommerce – Could not insert post

The last updates to WordPress core may issue the  “Could not insert post to database” error while using the klavyio plugin for wordpress. The fix is pretty simple and it’s needed because of the length constraints of the password field:

 

add_filter('woocommerce_klaviyo_new_cart_data', function($args) {
     $args['post_password'] = uniqid( 'klvct_' );
     return $args;
});

PHP CLI has stopped working – php, windows 7

Sometimes you might encounter an unexpected “CLI has stopped working” while running php in cli mode on windows 7. One of the possible causes is the fact that you’re running without administrator privileges. For example, taking the following symfony statement “php symfony doctrine:build-schema” in a cmd.exe without administrator privileges, might end up with the aforementioned error. To avoid that, click start and write “cmd” in the bottom search box > cmd.exe will appear > right click it and click Run as administrator. The error should not show up anymore.

Embedding multiple forms with symfony … hardcore :)

Well this should be one of the last posts about branch 1.x of symfony. The 2nd version should come to alpha soon so there is no real need to go further with it. Anyway … some time ago I desperately needed a quick and reliable way to embed multiple symfony forms on one page and submit them at once. I generally take the time to look into the source files, but this time i was in a hurry. So this is the “hacky” way i got around:

function executeMoo(sfWebRequest $request) {
$this->forms = array();

$it = 0;

foreach($some_model as $s) {

$f = new MooForm($s);

$f->getWidgetSchema()->setNameFormat('foo[' . $form->getName() . $it . '][%s]');

$this->form->embedForm($it, $form);
$this->forms[] = $this->form;
$it++;

}
}

The presentation part should be as simple as:

<form ...>
<table>
<tr>
<td><table>
<?php
foreach($forms as $form) :
   echo $form;
endforeach;
?>
</table></td>
</tr>
</table>
</form>
</pre>

Ok now for the validation part:

public function executeSubmit_Foo(sfWebRequest $request) {
         $this->forward404Unless($request->isMethod(sfRequest::POST));

   	$base_forms = $request->getParameter('foo');
    
	foreach($base_forms as $base_form) {
		$f = new MooForm();
		$f->bind($base_form,null);
		if($f->isValid()) {
			$f->save();			
		}
	}
}

What’s the catch?
Well the catch is in this line: $f->getWidgetSchema()->setNameFormat(‘foo[‘ . $form->getName() . $it . ‘][%s]’);
What it really does? it generates the form fields like foo[‘forms_name1′] … so the only thing you have to do is grabbing the foo var from request and looping through to get the embedded forms.
Sure there are better ways, but this worked nice with a minimum ammount of time spent.
Hope it helps.

[rb]Custom doctrine count query

Sometimes you may need to use count with the index column rather than *, because of some dark corners of sql driven databases. Though this is somehow rare, this is how you could do it with Doctrine … this example is part of a symfony 1.4 project(place the file in any of the /lib dirs … app ones or global one):

<?php

class Custom_Doctrine_Query extends Doctrine_Query {

public static function create($conn = null, $class = null)
{
if ( ! $class) {
$class = 'Custom_Doctrine_Query';
}
return new $class($conn);

}

public function getCustomCountSqlQuery()
{
// triggers dql parsing/processing
$this->getSqlQuery(array(), false); // this is ugly

// initialize temporary variables
$where   = $this->_sqlParts['where'];
$having  = $this->_sqlParts['having'];
$groupby = $this->_sqlParts['groupby'];

$rootAlias = $this->getRootAlias();
$tableAlias = $this->getSqlTableAlias($rootAlias);
$primaryKey = $tableAlias . '.' .  $this->_queryComponents[$rootAlias]['table']->getColumnName( $this->_queryComponents[$rootAlias]['table']->getIdentifier());

// Build the query base
$q = 'SELECT COUNT(' .  $primaryKey . ') AS ' . $this->_conn->quoteIdentifier('num_results') . ' FROM ';

// Build the from clause
$from = $this->_buildSqlFromPart(true);

// Build the where clause
$where = ( ! empty($where)) ? ' WHERE ' . implode(' ', $where) : '';

// Build the group by clause
$groupby = ( ! empty($groupby)) ? ' GROUP BY ' . implode(', ', $groupby) : '';

// Build the having clause
$having = ( ! empty($having)) ? ' HAVING ' . implode(' AND ', $having) : '';

// Building the from clause and finishing query
if (count($this->_queryComponents) == 1 && empty($having)) {
$q .= $from . $where . $groupby . $having;
} else {
// Subselect fields will contain only the pk of root entity
$ta = $this->_conn->quoteIdentifier($tableAlias);

$map = $this->getRootDeclaration();
$idColumnNames = $map['table']->getIdentifierColumnNames();

$pkFields = $ta . '.' . implode(', ' . $ta . '.', $this->_conn->quoteMultipleIdentifier($idColumnNames));

// We need to do some magic in select fields if the query contain anything in having clause
$selectFields = $pkFields;

if ( ! empty($having)) {
// For each field defined in select clause
foreach ($this->_sqlParts['select'] as $field) {
// We only include aggregate expressions to count query
// This is needed because HAVING clause will use field aliases
if (strpos($field, '(') !== false) {
$selectFields .= ', ' . $field;
}
}
// Add having fields that got stripped out of select
preg_match_all('/`[a-z0-9_]+`\.`[a-z0-9_]+`/i', $having, $matches, PREG_PATTERN_ORDER);
if (count($matches[0]) > 0) {
$selectFields .= ', ' . implode(', ', array_unique($matches[0]));
}
}

// If we do not have a custom group by, apply the default one
if (empty($groupby)) {
$groupby = ' GROUP BY ' . $pkFields;
}

$q .= '(SELECT ' . $selectFields . ' FROM ' . $from . $where . $groupby . $having . ') '
. $this->_conn->quoteIdentifier('dctrn_count_query');
}

return $q;
}

public function count($params = array())
{
$q = $this->getCustomCountSqlQuery();
$params = $this->getCountQueryParams($params);
$params = $this->_conn->convertBooleans($params);

if ($this->_resultCache) {
$conn = $this->getConnection();
$cacheDriver = $this->getResultCacheDriver();
$hash = $this->getResultCacheHash($params).'_count';
$cached = ($this->_expireResultCache) ? false : $cacheDriver->fetch($hash);

if ($cached === false) {
// cache miss
$results = $this->getConnection()->fetchAll($q, $params);
$cacheDriver->save($hash, serialize($results), $this->getResultCacheLifeSpan());
} else {
$results = unserialize($cached);
}
} else {
$results = $this->getConnection()->fetchAll($q, $params);
}

if (count($results) > 1) {
$count = count($results);
} else {
if (isset($results[0])) {
$results[0] = array_change_key_case($results[0], CASE_LOWER);
$count = $results[0]['num_results'];
} else {
$count = 0;
}
}

return (int) $count;
}

}

The usage of the above class should be something like this:

$query = Custom_Doctrine_Query::create()->from('TargetTable t');
$count = $query->count();

or the bulky way omitting the static create method:

$query = Doctrine_Query::create(null, 'Custom_Doctrine_Query')->from('TargetTable t');
$count = $query->count();

The result of the above queries should be something like “SELECT COUNT(index_field) from target_table”.

WTH swiftmailer

Now it’s kindda obvious that swift mailer is the best php mail library, but as any other great php library it sometimes lets you right in the middle of nowhere, when you’re thinking everything should be fine. This was the case with a freshly downloaded version … everything went fine until Swift_KeyCache_KeyCacheInputStream interface not found in … to shorten the story … swift looks for that interface which is expected to be in the file KeyCache.php … the declaration seems to be missing from the downloaded package … the fix is pretty simple(though there is probably a good reason why it isn’t there anymore, but for a quick fix will do) … open /classes/Swift/KeyCache.php and add these lines:

interface Swift_KeyCache_KeyCacheInputStream extends Swift_InputByteStream
{

	public function setKeyCache(Swift_KeyCache $keyCache);
	
	public function setNsKey($nsKey);
	public function setItemKey($itemKey);
	public function setWriteThroughStream(Swift_InputByteStream $is);
	public function __clone();
}

save it … and you’re good to go.

[rb]symfony’s 1.4 sfForm isValid()

Someone asked me a few days ago how can he use the sfform validation feature to validate an object created “by hand”. While i’m not quite sure yet of the usage of such a thing, here’s my approach(we’ll assume we have a table called Selections with 4 fields like id(incremental/key/bigint), target_id(bigint), type(varchar), name(varchar)):

public function executeAdd(sfWebRequest $request) {
if($request->isXmlHttpRequest()) {

$this->setLayout(false);

$this->forward404Unless($id = $request->getParameter('id'));
$this->forward404Unless($type = $request->getParameter('type'));
$selection = new Selections();
$selection->setTargetId($id);
$selection->setType(ucfirst($type));
$selection->setName('DEFAULT');

$form = new SelectionsForm(null, array(), false);
$values = $selection->toArray();
$form->bind($values);

if($form->isValid()) { $form->save(); echo 'OK'; }
else {
echo 'ERROR';
}

return sfView::NONE;
} else $this->forward404();
}

[rb]Debug a symfony object

While the symfony framework is quite intuitive and mostly easy to understand you might sometimes need to debug an object to see it’s methods or simply have a general overview(if you’r lazy enough not to check the official documentation). This might come handy sometimes:

 <?php

class Debugger {
 public static function debug($class, $exiting = true) {
if(!is_object($class)) return; 
$methods = get_class_methods($class);
 natsort($methods);
 echo '<h1>' . get_class($class) . '</h1>';
 echo '<hr size="1" />';
 array_walk($methods, array(self, "format"));        
 if($exiting) exit();
 }

 public static function format(&$item1, $key) {
 if(strpos($item1,"__") > -1) $item1 = '<span style="background: #ff0000">' . $item1 . '</span>';
 elseif(strpos($item1, "get") > -1) $item1 = '<span style="background: #cceeff">' . $item1 . '</span>';
 elseif(strpos($item1, "set") > -1) $item1 = '<span style="background: #eeffcc">' . $item1 . '</span>';
 else $item1 = '<span style="background: #ddd">' . $item1 . '</span>';
 echo $item1 . "<br />";
 }
}

?>

Save it in the lib dir of your application under the name Debugger.php then call it like this

Debugger::debug($symfony_object_you_want_to_see);

[rb]Get relative url with symfony

While using symfony in a subdirectory of your domain you might want to get the absolute URL path of you web directory. This should help you:

function getUrlLocation() {
	$s = $_SERVER['DOCUMENT_ROOT'];
	$t = explode(DIRECTORY_SEPARATOR, sfConfig::get('sf_web_dir'));
	$tx = explode(DIRECTORY_SEPARATOR,$s);
	$dif = array_diff($t,$tx);
	return implode(DIRECTORY_SEPARATOR, $dif);
}

A practical example would be redirecting from a public module to the backend module for example. That would be accomplished by using the following code:

header("Location: /". getUrlLocation() . "/backend.php"); exit();