cakedc / utils Goto Github PK
View Code? Open in Web Editor NEWUtils Plugin for CakePHP
Home Page: http://cakedc.com
License: Other
Utils Plugin for CakePHP
Home Page: http://cakedc.com
License: Other
thanks CakeDC for this awesome plugin ;)
sorry for my bad english :(
i have a problem :
when i use Model::deleteAll() instead of Model::delete() the behavior doesn't work any more and i have a "Hard Delete" !!
Reported by dien | April 4th, 2011 @ 08:24 PM
From
$prev = $Model->find('first', array(
'contain' => array(),
'fields' => array("{$Model->alias}.{$Model->tinySlug}", "{$Model->alias}.created"),
'order' => "{$Model->alias}.created DESC"));
to
$prev = $Model->find('first', array(
'contain' => array(),
'fields' => array("{$Model->alias}.{$Model->tinySlug}", "{$Model->alias}." . $this->settings[$Model->alias]['order']),
'order' => "{$Model->alias}.{$this->settings[$Model->alias]['order']} DESC"));
new setting default:
protected $_defaults = array(
'tinySlug' => 'tiny_slug',
'codeset' => '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
'order' => 'created'
);
In master there is GravatarHelper::url though in develop there is GravatarHelper::imageUrl methods.
The later was renamed for PHP 5.4 compatibility.
The change landed in develop, some time again, though it's still not showing in master?
it loads the cvs file but does not import any information into my model.
So we had a requirement for a project that stated "Nothing to be hard deleted", so I have implemented SoftDelete on every model through AppModel.
Since then we had a few problems whereby our user management system (which is coded as a plugin) seemed to lose track of where the User model is, we called the plugin models in the $uses array in AppController:
public $uses = array('Usermgmt.User', 'Usermgmt.UserDetail');
When SoftDelete is removed from AppModel:
debug(get_class($this->User));
Shows $user however it shows "AppModel" when it is enabled. I assume this is because it isnt being loaded with PluginName.User in the behaviour?
Thanks :)
There are some conditionals in beforeSave() that just return; which is failing my save(); when I change them to return true it works.
Using 2.0 branch with CakePHP 2.0. Line 83 in particular is where I was failing.
if (empty($Model->data[$Model->alias])) {
return;
} else if (empty($Model->data[$Model->alias][$this->settings[$Model->alias]['label']])) {
return;
} else if (!$this->settings[$Model->alias]['update'] && !empty($Model->id) && !is_string($this->settings[$Model->alias]['trigger'])) {
return; // this is returning
}
Should these be return true?
I am saving objects from an API in a loop. I have AppModel::cacheQueries set to true. When saving an array of object with the same name, I get ( as expected ) SQL errors saying that it failed to add entries because of duplicate values for the field slug
, which i have set to be unique.
( solution#1 ) I know I can ( and should ) simply turn off cacheQueries off before i initialize the loop but I was curious to know if ( solution#2 ) this is something the SluggableBehavior should do on its own. Another alternative ( solution#3 ) would be not to make my slug
field unique. What would be the proper solution of those 3?
Seems like the PingBackable behaviour wasn't tested, at least through lint:
php -l PingbackableBehavior.php
PHP Fatal error: Can't use function return value in write context in PingbackableBehavior.php on line 63
Errors parsing PingbackableBehavior.php
Unfortunately I don't use this part of the Utils plugin so I haven't really looked through it much yet.
before I submit a PR I wanted to get the community and CakeDC's thoughts on these questions. Please Let me know if they are not clear and I will provide more details:
If label used to generate the slug from has no alpha-numeric characters in it, such as "$$$", the generated slug is an empty string. Either add ability to allow/disallow empty string slug, or just default to not allow empty string slug.
If generated slug is empty string, and that is not desired, use - for the slug value.
Hello,
I've an error with your RefererComponent.
I'm currently using the master branch with a CakePHP 2.1 installation.
The problem is that I'm getting this error :
call_user_func_array() expects parameter 1 to be a valid callback, class 'RefererComponent' does not have a method 'beforeRender'
I think that's because of the declaration of the class :
class RefererComponent extends Object {
It should not be that (according to documentation) :
class RefererComponent extends Component {
Thanks
When finding duplicates for a title, the SluggableBehavior
does this:
if ($settings['unique'] === true) {
$conditions[$Model->alias . '.' . $settings['slug'] . ' LIKE'] = $slug . '%';
} else if (is_array($settings['unique'])) {
foreach ($settings['unique'] as $field) {
$conditions[$Model->alias . '.' . $field] = $Model->data[$Model->alias][$field];
}
$conditions[$Model->alias . '.' . $settings['slug'] . ' LIKE'] = $slug . '%';
}
So if you're adding a record with the title "Test", it'll also find "Test Page". So you'll end up with the slug "test-1" (i.e.). There should be a check if the current slug is the $duplicates
array.
My solution for this issue:
if (!empty($duplicates)) {
$duplicates = Set::extract($duplicates, '{n}.' . $Model->alias . '.' . $settings['slug']);
if (in_array($slug, $duplicates)) {
$startSlug = $slug;
$index = 1;
while ($index > 0) {
if (!in_array($startSlug . $settings['separator'] . $index, $duplicates)) {
$slug = $startSlug . $settings['separator'] . $index;
$index = -1;
}
$index++;
}
}
}
Note the "in_array".
Reported by dien | February 25th, 2011 @ 10:55 PM
if i use this script:
pubic function create(){
for ($i = 0; $i < 3; $i++) {
$this->Multi->create();
$this->Multi->save($this->data);
}
}
then 3 rows is created with tiny_slug field is as same .
And this line in Tinysluggable:
private function __getNextSlug(&$Model) {
$new = '';
$prev = $Model->find('first', array(
'contain' => array(),
'fields' => array("{$Model->alias}.{$Model->tinySlug}", "{$Model->alias}.created"),
'order' => "{$Model->alias}.created DESC"));
order by created field , but in 1s , 10 fields can be created, i don't know if it is order right .
Edit I fixed this, it is because i set cacheQueries = true.
I've just got back to my project after a month or so off, and after upgrading CakePHP (I think this was the cause), I'm now getting a Strict warning on every page that uses the Gravatar helper:
Declaration of GravatarHelper::url() should be compatible with Helper::url($url = NULL, $full = false)
I'm not 100% sure how you'd want to patch this tbh, possibly use a different name for the method, or just hack the same parameters in?
Could you update I18nCountry.php to use __d('Utils','whatever) for the printable names (and elsewhere) instead of __('whatever')? When extracting strings I get hundreds of the strings for the country names in my default.pot file and I think they should have their own domain.
Thanks
Hello,
just noticed this strict error appears on latest CakePHP 2.4 with PHP 5.4:
Strict (2048): Declaration of CsvImportBehavior::setup() should be compatible with ModelBehavior::setup(Model $model, $config = Array) [APP/Plugin/Utils/Model/Behavior/CsvImportBehavior.php, line 217]
CsvImportBehavior.php :
public function setup(Model &$Model, $settings = array()) {
removing & fixes it..
public function setup(Model $Model, $settings = array()) {
Thanks,
Andras
Validation rules merging between child and parent class should be moved from the beforeValidate() to the setup() method of the behavior. This way, Cake is aware of required rules vía FormHelper when displaying a form.
public function setup(Model $Model, $config = array()) {
$_defaults = array(
'inheritanceField' => 'type',
'method' => 'STI',
'fieldAlias' => $Model->alias);
$this->settings[$Model->alias] = array_merge($_defaults, $config);
$Model->parent = ClassRegistry::init(get_parent_class($Model));
$Model->inheritanceField = $this->settings[$Model->alias]['inheritanceField'];
$Model->fieldAlias = $this->settings[$Model->alias]['fieldAlias'];
if ($this->settings[$Model->alias]['method'] == 'CTI') {
$this->classTableBindParent($Model);
if (!empty($Model->parent->validate)) {
$Model->validate = Set::merge($Model->parent->validate, $Model->validate);
}
}
}
Do you see any drawback on this implementation?
I've reached a point in my project where this would be ideal.
I wanted to make a note of it here as I think it would be a valuable addition to the behaviour.
I will implement something similar in my projects behaviour and once I have a good implementation, if people think it's helpful, I can submit a pull request for it. I assume it would be best submitted on a feature branch?
Thanks
I have found an issue when using the InheritableBehavior, that causes complex data types (date/time types) to fail during validation.
Having an inheritance setup with CTI like this:
class Person {
public $validate = arary(
'name' => 'notempty',
'birth' => 'date'
);
}
...
class Player extends Person {
public $validate = arary(
'team' => 'notempty',
);
public $actsAs = array(
'Utils.Inheritable' => array(
'method' => 'CTI',
)
)
}
And generating a form like this:
echo $this->Form->create('Player');
echo $this->Form->input('name');
echo $this->Form->input('birth');
echo $this->Form->input('team');
echo $this->Form->end();
When trying to save Player, it will fail on the 'birth' field validation, because:
A workaround I found for this is looping through the complex type data (arrays/objects) in the beforeValidate() behavior method and calling parent to deconstruct them:
public function beforeValidate(Model $Model, $options = array()) {
if ($this->settings[$Model->alias]['method'] == 'CTI' && !empty($Model->parent->validate)) {
$Model->validate = Set::merge($Model->parent->validate, $Model->validate);
}
foreach ($Model->data[$Model->alias] as $fieldName => $fieldValue) {
if (is_array($fieldValue) || is_object($fieldValue)) {
$fieldValue = $Model->parent->deconstruct($fieldName, $fieldValue);
$Model->data[$Model->alias][$fieldName] = $fieldValue;
}
}
return true;
}
I've run the behavior tests after adding this and all passed (Should I build extra tests for this?). I will submit a PR if you think is a proper fix.
hi,
i have tow models
Groupestablishment hasMany Establishment
i added the two fields 'deleted' and 'deleted_date' to the tables 'groupestablishments' and 'establishments'
i add also this line to the Groupestablishment Model
public $hasMany = array('Establishment' => array('dependent' => true));
but when i delete(SoftDelete) a Groupestablishment it update only the 'groupestablishments' table :(
it doesn't update the associated model
have i miss anything ??
thanks
Reported by Dunhamzzz | August 17th, 2011 @ 07:35 AM
When executing a GravatarHelper request I get this fatal error:
Fatal error: Call to a member function image() on a non-object in /srv/share/cakephp/2.0/plugins/Utils/View/Helper/GravatarHelper.php on line 91
It seems that despite containing $helpers = array('Html'), the HtmlHelper is not loaded. I've tried this with both 2.0 branch and 2.0-dev (code is the same in both anyway).
line 203
['field_date'] . ' <='] = date('Y-m-d H:i');
to
['field_date'] . ' <='] = date('Y-m-d H:i:s');
Sorry, i can't pull a request , it keep show a 404 page.
This problem cause confuse for everyone
May I make the request to update the typo in the Readme file that mentions a snippet to be used in the AppController when it should be in the AppModel ? It looks like the edit has already been done in the development branch. However, it does not seem right that the typo should wait for a pull of development ( which I am sure requires testing ) to rectify a typo that is a pretty big deal.
I have a patch created from Master ( too keep everything else the same ) and I am ready to do a PR if you guys think that it makes sense to update the readme now.
Is there any reason why SoftDeleteBehavior would not support only one deleted date field? A record would be soft deleted only when deleted date field is not null. It would make database tables simpler.
I wanted to add list items to the top of the List, using the ListBehavior
. After checking the code, I saw that it wasn't possible.
So I added some changed to it, so it was able to do that.
Added the default setting:
protected $_defaults = array(
'positionColumn' => 'position',
'scope' => '',
'validate' => false,
'callbacks' => false,
'addToTop' => false
);
Added check to the beforeSave
public function beforeSave(Model $model) {
extract($this->settings[$model->alias]);
if (empty($model->data[$model->alias][$model->primaryKey])) {
if ($addToTop) {
$this->__addToListTop($model);
} else {
$this->__addToListBottom($model);
}
}
return true;
}
I thought that it should work like that, since there was already a method to add items to the top. But I got some errors while using it.
Set the position in the current data
private function __addToListTop($model) {
$positionColumn = $this->settings[$model->alias]['positionColumn'];
$model->data[$model->alias][$positionColumn] = 1;
return $this->__incrementPositionsOnAllItems($model);
}
Now it works fine. Wanted to share this, because it's a fine addition to the great behavior!
There appears to be a problem with the SoftDelete behavior (or a problem with it in combination with our configuration). We have fixed it for our situation, but keep in mind that this might be a fix for a problem that doesn't exist by default.
In the function _softDeleteAssociations there is a loop through parentmodels where the following check is done:
if($model->alias != $modelName)
{
continue;
}
Now if a model alias is, for example, 'Crm.Contact', everything is fine, but as soon as an association is defined in the following way, there is a problem.
'Address' => array(
'className' => 'Crm.Address',
'foreignKey' => 'foreign_id',
'conditions' => ....
The problem here is that the $model->alias ("Address") is not equal to the $modelName ("Crm.Address") causing the check to fail and the is_deleted condition not to be applied.
My fix for this is to replace the simple "if($model->alias != $modelName)" check with:
if((!empty($model->plugin) && strstr($model->plugin.'.', $model->alias)===false ? $model->plugin.'.' : '') . $model->alias != $modelName) {
I keep getting an "invalid record" error when executing Toggleable->toggle() for an existing record:
https://github.com/CakeDC/utils/blob/master/Model/Behavior/ToggleableBehavior.php#L92
!$Model->exists(true) always returns true, even if $Model->id is set and there is a record with that id in the database. If I remove "true" it works as expected.
I wrote this test for sluggable behavior (for 1.3)
/**
* Test save unique2
*
* @return void
*/
public function testSaveUnique2() {
$this->Model->create(array('title' => 'Puertas para muebles'));
$this->Model->save();
$this->Model->create(array('title' => 'Puertas'));
$this->Model->save();
$results = $this->Model->find('all', array('conditions' => array('title LIKE' => 'Puertas%')));
$this->assertEqual(count($results), 2);
$this->assertEqual($results[0]['SluggedArticle']['slug'], 'puertas_para_muebles');
$this->assertEqual($results[1]['SluggedArticle']['slug'], 'puertas');
}
This fail with this message:
Equal expectation fails at character 7 with [puertas_1] and [puertas] at [/home/gaston/public_html/multiplacas/plugins/utils/tests/cases/behaviors/sluggable.test.php line 114]
/home/gaston/public_html/multiplacas/plugins/utils//tests/cases/behaviors/sluggable.test.php -> SluggableTest -> testSaveUnique2
If "Puertas*" is before "Puertas", the test fail.
There are 2.0 and 2.0-dev branches in this repo which may confuse users. And it was not clear which branch is 'stable'. I had an issue (Btree method name) that turns out to be merged in master branch, but not in 2.0 nor 2.0-dev.
I'd like to suggest retiring these two branches or merge them into 1.
Swapping over to composer install of utils, it's erroring out with the following
Failed to clone https://github.com/cakedc/utils.git via git, https protocols, aborti
ng.
- git://github.com/cakedc/utils.git
fatal: remote error:
Repository not found.
- https://github.com/cakedc/utils.git
As far as I can see, the url is OK except for case. it should be:
git://github.com/CakeDC/utils.git
Trying to git clone the cakedc one manually fails, CakeDC works.
The following example:
class Person extends AppModel
{
var $hasOne = array('Address');
}
class Client extends Person
{
var $hasOne = array('BankAccount');
}
doesn't work correctly as Client->hasOne and Person->hasOne are not merged anywhere during model initialization (as opposed to belongTo fields). Same thing happens with hasMany.
Turns out the sluggable behaviour won't replace the ™
or ®
characters
I have a threaded find result which I do pass to the helper.
The helper should help me to generate a navigation like it is shown here:
http://twitter.github.com/bootstrap/components.html#navs
CODE OUTPUT NEEDED:
http://bin.cakephp.org/view/1760699433
I tried to get it work with a node element which looks like this:
http://bin.cakephp.org/view/1056010096
Also a var_export array is given to test.
The problem is, that the vars $firstChild and $lastChild always do give me boolen true back on each child item so that I can't figure out if the child ist the last item of the dropdown menu to close it with a closing ul tag.
A other solution would be to extend the helper code to pass the needed class defintion for the nested ul list as a second argument. At the moment the main ul and li class can be defined but the list is basicly correctly generated by the helper.
Plz add more examples/doc for other behaviours and components
Reported by sibljon | November 3rd, 2010 @ 09:46 PM
It seems that the conditions are added to the database query in SoftDelete::beforeFind() callback to ignore records that have been soft deleted. Is there any way around this?
I have found a strange issue when using the SoftDelete behavior which causes the runtime to be disabled, when using paginate()
Issue
When calling purgeDeletedCount()
above the collection of data in your controller, the current models runtime is set to false, allowing deleted items to be present in the dataset.
Short term fix
You need to move the search for data above your call to purgeDeletedCount()
.
Examples
<?php
// The results returned here will include deleted items
$this->set('purgeable', $this->Content->purgeDeletedCount());
$this->set('contents', $this->paginate('Content'));
// This will work as expected
$this->set('contents', $this->paginate('Content'));
$this->set('purgeable', $this->Content->purgeDeletedCount());
I haven't tested this using the Paginator
component setup in $components
and $this->Paginator->paginate()
in the controller.
I reported this as a cake bug http://cakephp.lighthouseapp.com/projects/42648-cakephp/tickets/3469-saving-with-empty-fields#ticket-3469-3 which affects InheritableBehaviour
On Cake 2.2.3 I have class B extends class A using CTI.
The problem is that, if I save class B with all class B's fields empty and only setting class A fields, afterSave is not trigger and so nothing gets saved.
Ideally, an empty model B row should be added and then the afterSave trigger should save model A data.
The following example:
class Person extends AppModel
{
var $hasOne = array('Address');
}
class Client extends Person
{
var $hasOne = array('BankAccount');
}
doesn't work correctly as Client->hasOne and Person->hasOne are not merged anywhere during model initialization (as opposed to belongTo fields). Same thing happens with hasMany.
The following assertion with the above models will fail:
$Client = ClassRegistry::inity('Client');
$this->assertTrue(isset($Client->Address));
This was documented as Issue #83 but closed due to a typo and never reopened.
Correct me if I am wrong, but it looks like if the beforeDelete method returns true, the model will go ahead and do a hardDelete.
https://github.com/CakeDC/utils/blob/develop/Model/Behavior/SoftDeleteBehavior.php#L130 returns the value returned by SoftDeleteBehavior::delete() which is true on a successful save. Thus, after the SoftDeleteBehavior::beforeDelete(), Model::delete() will still run.
Either I am not doing something extra ( that I should be doing ) in the controller/model or that line should be returning false all the time to avoid Model::delete() from running
When running the tests on this plugin:
Console/cake test Utils AllUtilsPlugin
fails with:
Fatal error: Cannot redeclare class Content in [...]\app\Plugin\Utils\Test\Case\Model\Behavior\InheritableTest.php on line 18
Reported by dien | March 20th, 2011 @ 04:03 AM
function beforeSave(&$Model, $options = array()) {
$Model->data = $Model->serialize($Model->data);
return true;
}
It will happen error when validate notEmpty in "data" field:
arning (2): preg_match() expects parameter 2 to be string, array given [CORE\cake\libs\validation.php, line 946]
If Serializable Behavior serialize "data" field in beforeValidate it will not happen.
https://github.com/CakeDC/utils#softdelete-behavior
delete needs to be added in AppModel or AppController
I have tried and tried, but for some reason soft delete does not work recursively. I have dependent set to true in all my model. It will set delete to 1 for the one I clicked to delete, but then doesn't set any of the childrens' delete to 1.
In my experience the following function only works when placed in AppModel, not AppController. I don't expect one, but an explanation would be cool:
public function delete($id = null, $cascade = true) {
$result = parent::delete($id, $cascade);
if ($result === false && $this->Behaviors->enabled('SoftDelete')) {
return (bool)$this->field('deleted', array('deleted' => 1));
}
return $result;
}
I have a Photos model with MySQL table "photos" with columns "deleted" (INT(1), default 0) and "deleted_date" (DATETIME, default NULL). The save() function at the end of the SoftDeleteHelper's delete() function is returning false; however, the "deleted" field is set to 1, and the "deleted_date" is set to the current DATETIME. The SQL query is also valid:
UPDATE photos SET deleted = '1', deleted_date = '2010-10-24 18:08:56', modified = '2010-10-24 18:08:56' WHERE photos.id = 3
Why does the save() (and hence delete()) function return false?
The following test fails on my side:
public function testClassTableCreateCount() {
$initial_count = $this->Asset->find('count');
for ($i=0; $i<10; $i++) {
$this->Image->create(array(
'title' => 'BSD logo',
'description' => 'Daemon powers',
'file_name' => 'bsd.bmp',
'file_size' => '653445',
'content_type' => 'image/bitmap'));
$this->Image->save();
}
$final_count = $this->Asset->find('count');
$this->assertEqual($final_count-$initial_count, 10);
}
The problem is that when creating Image, the fields override all Link data.
Also, notice the strange way the fixture was created:
AssetFixture:
array('id' => 1, 'title'=> 'soccuer image', 'description'=> 'amazing shot...'),
array('id' => 2, 'title'=> 'animal image', 'description'=> 'very disturbing'),
array('id' => 11, 'title'=> 'home page link', 'description' => 'link back to home page'),
array('id' => 12, 'title'=> 'google', 'description' => 'Google is the search engine'),
ImageFixture:
array('id' => 1, 'file_name'=> 'soccer_worldcup.jpg', 'file_size' =>' 53422', 'content_type' => 'image/jpeg'),
array('id' => 2, 'file_name'=> 'dog.png', 'file_size'=>'431234', 'content_type'=>'image/png'),
LinkFixture:
array('id' => 11, 'url'=> 'http://cakephp.org'),
array('id' => 12, 'url'=> 'http://google.com'),
This is why I had to save 10 Images to be able to show this bug.
Model->exists($id)
returns true when a record has been soft deleted. It does this because, Model->exists($id)
uses 'callbacks' => false
when calling Model->find()
.
** My fix doesn't work. It breaks undelete()
. ** I guess you shouldn't rely on Model->exists($id)
when using this behavior.
This can be fixed by adding the following to AppModel.
// This goes in AppModel.php
public function exists($id = null) {
$usingSoftDelete = false;
foreach ($this->Behaviors->methods() as $key => $method) {
$usingSoftDelete = $usingSoftDelete || (is_array($method) && ($method[0] == 'SoftDelete'));
}
if ($usingSoftDelete) {
/* Model.php, public function exists($id), with additional condition */
if ($id === null) {
$id = $this->getID();
}
if ($id === false) {
return false;
}
$conditions = array($this->alias . '.' . $this->primaryKey => $id,
$this->alias . '.deleted' => 0);
$query = array('conditions' => $conditions, 'recursive' => -1, 'callbacks' => false);
return ($this->find('count', $query) > 0);
}
return parent::exists($id);
}
geting this error when using csvImporter
Database Error
Error: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'getImportErrors' at line 1
Referer (referrer) component installed and working (Cake 2.4). The referer var is available in my view, and I have added it to my form(s).
Works well if the form submits successfully, but if the form is submitted with errors more than once, the original referer is overwritten with the url of the form.
I have dabbled in trying to save the value in the session, but this quickly becomes unpredictable if the user moves away from a page mid-way through an operation.
Is there a way to retain the original referer over multiple failed form submissions?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.