Jump to content

ryan

Administrators
  • Posts

    16,772
  • Joined

  • Last visited

  • Days Won

    1,531

Everything posted by ryan

  1. The query in question is the first one executed by PW and this is what you'll see if there's a DB connection error. That's not ideal, and I'm not sure how I missed that error check the first time around–I'm updating the Database class to detect connection errors and throw a more appropriate error message. That way we can see exactly why it can't connect.
  2. Thanks guys, let me know how it works for you. I like your ideas here, good thinking! Perhaps we just maintain another section of modules that represents the uninstalled list. At the moment I'm a little scared of an "install all" in the same request, but perhaps I shouldn't be–definitely something to think about and perhaps implement in the future.
  3. See here: http://processwire.com/talk/index.php/topic,159.0.html If you can't change your mysql settings, you can also use the [slower] %= selector operator rather than the *= and that will support words of any length.
  4. I don't know much about Magento or what the SOAP client modules are. I have a strong preference for services built around HTTP/REST rather than SOAP. But so long as it's providing the services in some form, that means that it's probably a reasonable task to integrate. Magento also seems like a pretty solid system. Though admittedly, I've tried to install and use it before and found it a little overwhelming... Drupal/UberCart turned out to be a better fit for what I needed. But I think Magento is probably stronger overall. Let us know what you find and how it goes.
  5. If using $page->parent in a string context, it's actually going to resolve to the ID. But I think it's better to be clear about what property you are checking. I recommend doing this: if($page->parent->id > 1) The homepage always has an ID of 1 and that's a factor you can count on in PW.
  6. This is something I don't know much about yet and need to do more research. You've got me curious. Looking at Drupal7, it looks like they do it with PHP, though only if one specifically enables some page_compression and cache options. I only see reference to it in their /includes/bootstrap.inc for serving pages from the cache. It looks like it involves checking a lot of $_SERVER variables to verify gzip support, delivering a "content-encoding: gzip" header and spitting out the gzipped data when appropriate. They create the gzipped data with PHP's gzencode function. It appears that they only use it for delivering data from the cache. That makes me think that the gzencode is potentially slow and they are caching and performing the gzencode after delivering a page where it can be picked up from the cache by the next request. What's interesting is that they gzip the cache data even if not supported by the client and they gzinflate it at runtime for clients that don't support it. I suppose this makes sense, and a good way to keep smaller cache sizes. This is something we'll probably want to implement in PW's core PageRender module at some point.
  7. Thanks Antti, glad that it's working alright and that the dates imported how they should. That's interesting that your CSV file had unescaped quotes in it. That will confuse any CSV parser. What did you use to export the CSV? Nico's right that quotes should be escaped with a backslash.
  8. I put in module dependencies into the 2.2 dev version yesterday, and just wanted to explain how they work, both for the user side and the developer side. What it means and what it does "Module dependency" means that when you install plugin modules, they can now require that other prerequisite modules are installed first before they are. Likewise, if one module requires another, then it prevents modules in use from being uninstalled. Ultimately this leads to more clarity in the system, and makes it easier for one module to rely upon another. Likewise, it prevents the issue of being able to uninstall one module that's actively used by another. It's a convenience and a safety. The module dependency update in 2.2 also adds the ability for related modules to establish a simple parent-child relationship. One module can say that it is responsible for the installation of another, and so you can have modules installed or uninstalled as a group. Meaning, if you installed a plugin that includes 3 different modules to operate, then PW will only let you install the one designated by the developer, and the others will be installed automatically immediately after it. The same goes for the uninstall process. How to use now Attached are a couple screenshots that show how it looks from the Modules page in PW. If you want to test out dependencies, this feature is in the "dev" branch of the current ProcessWire distribution. If you are up to date on your git pulls, or you just installed a fresh copy with git, then you just "git checkout dev" to get to it. Of course, only do this on a test or development site, not a production site. FOR MODULE DEVELOPERS Using these dependencies is completely optional from a module development standpoint. While these dependencies don't exist in the current stable version of PW (2.1) there's no harm in implementing them now, as PW 2.1 will just ignore them. To test dependencies in PW 2.2, you'll just want to switch to the dev branch as mentioned in the previous section. When to use dependencies If you know that your module needs some other module in order to run property, it's a good idea to take advantage of dependencies. Especially given how easy they are to implement. Another situation where you'd want to use dependencies is with plugins that include more than one module. For instance, a fictional plugin called "Log Master" may have an "autoload" module called LogMaster to hook into various things and log them, and another called ProcessLogMaster to display them in the admin. You don't want someone to be able to install ProcessLogMaster without first installing LogMaster. Furthermore, you might want to have ProcessLogMaster automatically install (and uninstall) at the same time as LogMaster. In this light, dependencies can add a lot of convenience for the person installing your module, and less support and documentation burden for you. Using the "requires" dependency Dependencies are defined in your getModuleInfo() function. To establish a dependency, all you need to do is add a "requires" property to the array returned by your getModuleInfo() function. That "requires" property may be a string or an array. If it's a string, it's assumed to contain just the name of one module. If it's an array, it's assumed contain one or more module names. Lets say that I was creating a "Hello World" module that required the "LazyCron" module. Here's how you'd do it: HelloWorld.module <?php public static function getModuleInfo() { return array( 'title' => 'Hello World', 'version' => 101, 'author' => 'Ryan Cramer', 'summary' => 'Just an example', 'requires' => "LazyCron" // added this line ); ); You can also specify 'requires' as an array, which is what you'd want to do if you wanted to specify that multiple other modules are required (though you can of course use an array for 1 module too): HelloWorld.module <?php public static function getModuleInfo() { return array( 'title' => 'Hello World', 'version' => 101, 'author' => 'Ryan Cramer', 'summary' => 'Just an example', 'requires' => array("LazyCron", "AdminBar") // added this line ); ); That's all that you need to do to specify a module dependency. Once you do that, ProcessWire won't let your module be installed until LazyCron and AdminBar are installed. Likewise, ProcessWire won't let LazyCron or AdminBar be uninstalled so long as HelloWorld is installed. Using the "installs" dependency If you want to specify that your module installs and uninstalls other modules, then you should add an "installs" property to the array returned by getModuleInfo. Like with "requires", the property may be a string or an array, with an array is required for multiple items. Using this property is your module's way of telling ProcessWire that it is the parent of those modules and they should be installed–and uninstalled–at the same. Like with PW 2.1, your module's install() and uninstall() methods may handle the installation/uninstallation of any other modules too... but it doesn't have to. PW will automatically install/uninstall any modules specified in "installs" immediately after your module, unless your module already took care of it. It's a good idea to specify those child modules in your "installs" even if your install() function is already taking care of installing them. That way, PW can still note the relationship in the admin. Below are examples of how to add the "installs" property to your getModuleInfo(). We'll use the LogMaster example mentioned earlier on. LogMaster.module – parent module <?php public static function getModuleInfo() { return array( 'title' => 'Log Master', 'version' => 101, 'author' => 'Lumberjack Bob', 'summary' => 'Log all actions on your site', 'requires' => 'LazyCron', 'installs' => 'ProcessLogMaster' // added this line ); ); Now you've told PW that ProcessLogMaster should be installed at the same time as LogMaster. If LogMaster doesn't install ProcessLogMaster, then ProcessWire will install ProcessLogMaster automatically after it installs LogMaster. One thing to note about uninstalls: PW will only uninstall modules that specify the parent module in their "requires". If they don't, then PW will leave them installed when the parent module is uninstalled. After all, why should PW uninstall a module that doesn't require the other one being uninstalled? But I'm guessing that in most (not all) instances where you would use "installs", you'll also want to use "requires" with the child modules, pointing to the parent module: ProcessLogMaster.module – child module <?php public static function getModuleInfo() { return array( 'title' => 'Log Master (Process)', 'version' => 100, 'author' => 'Lumberjack Bob', 'summary' => 'Displays the logged actions in the admin', 'requires' => 'LogMaster', // added this line ); ); Using the above example, this ProcessLogMaster will be automatically uninstalled with LogMaster since it indicates that it requires LogMaster, and LogMaster indicates that it installs ProcessLogMaster. SCREENSHOTS 1. This shows how the module dependencies are highlighted on the Modules list page. Note that the install option is disabled for those modules that require another to be installed first. 2. This shows the screen that appears when you click on the LanguagesSupport module. It demonstrates the group of modules (children) connected with LanguageSupport (parent) module. 3. This shows an example of a module (FieldtypeComments) that has a module requiring it (CommentFilterAkismet). That CommentFilterAkismet module is an optional component to the Comments module, so is not installed by default when FieldtypeComments is installed. Since CommentFilterAkismet requires FieldtypeComments, CommentFilterAkismet would have to be uninstalled before FieldtypeComments could be uninstalled.
  9. I don't see it here but got an email about paginator get vars. Make sure you turn on 'allow page numbers' in your template settings because pagination requires that setting to work properly. It shouldn't use get vars for the page number.
  10. So long as you use limit=n, where n is some number greater than 1, PW will not load any more than n pages (or select the data from mysql). So paginating your selects is a good idea. The getTotal() method from the returned PageArray will contain the total number of found results (the total that would exist had there never been a limit). So the $pages->count() does little more than add a limit=2 to your selector and just returns the result of the $results->getTotal(). That count method is more for syntactic convenience, as PW already counts anything that goes through a find(limit>1). And the instances of where one would use pages->count() are pretty rare. But optimizing the count method to load 0 rather than 2 pages is on my to do list. I'm typing on a cell phone so somewhat limited in my response here, but to recap, everything you need to paginate is already included anytime you include a limit=n in your selector and using PW's pagination is recommended, especially when dealing with large data sets. There is obvious overhead relative to pure SQL queries, but I think it's very much worth it 99% of the time for the sites we build. Enable debug mode in your config.php to see the queries (from admin).
  11. I put in a lot of Language Support updates today, and put in the module dependency support while I was at it. One of the bigger things added was the multi language text fields. You can create new fields that using TextLanguage or TextareaLanguage (rather than Text or Textarea). You can also convert existing text fields to/from the multi-language versions. The multi language 'title' field isn't yet ready, but close. I also haven't yet put in a lot of testing into these multi language fields, so any help testing is appreciated. Before you grab this update, I recommend uninstalling the LanguageSupport modules from your existing install (if you have them), or starting from a fresh install before testing. Also, as always, don't use the dev branch in production. Lastly, the TextareaLanguage field doesn't yet work with TinyMCE yet. It's probably a simple fix, but I ran out of time to work on it today so should have an update there soon. I currently have the find() selectors designed to match values in either the current language OR default language. So if your 'summary' field is a TextLanguage field, Finnish is your current language and you execute something like this… $results = $pages->find("summary*=Antti"); …It's going to match pages that have "Antti" in the Finnish summary or Default language summary field. But it won't match in any other languages, unless you set one of them to be your language. I figured this is the behavior that most would want, but can also make it match only in the Finnish summary (or make it configurable per-field).
  12. I think this will depend somewhat on what format those dates will be in from your spreadsheet (CSV). If it's a unix timestamp, or any format consistent with what PHP's strtotime() will accept (which includes quite a lot of formats), then you should be able to import dates pretty easily. I think all you'd need to do is add FieldtypeDate to the list of allowed fieldtypes at the top of the modules: <?php protected $fieldtypes = array( 'FieldtypePageTitle', 'FieldtypeText', 'FieldtypeTextarea', 'FieldtypeInteger', 'FieldtypeFloat', 'FieldtypeEmail', 'FieldtypeURL', 'FieldtypeCheckbox', 'FieldtypeFile', 'FieldtypeDate' // add this line ); I don't have a good example to test from at the moment though will try to test it tomorrow. But let me know if you get a chance to test, and if that works I'll go ahead and add it to the module permanently. Looking at it now, I'm not sure why I didn't add it before. But it's the end of the day here so my mind is tired and I may be missing something.
  13. Nice update, thanks for posting!
  14. I think I understand. Try modifying the settings carried by the PageArray after your find() is performed, but before your pagination is output: <?php $results = $pages=find("something=something, limit=10"); if($user->isGuest() && $results->getTotal() > 50) { $results->setTotal(50); if($results->getStart() > 40) $results->setStart(40); } // then do your pagination
  15. The FormTemplateProcessor module was always intended to be a proof of concept and not much more than a starting point for people to customize and build from. At present it's not designed to deal with multiple instances of itself (though could easily be updated to). When it looks to see if a form is submitted, it is checking $input->post->submit. If you've got two forms on the same page, then they are both going to be detect that submit. A better solution would be for it to assign a unique variable (or submit button name) that goes with each form so that one can't be confused for another. When we build a proper form builder/processor, we'll definitely be handling all this stuff in the module. But until then I still think it's better to manage your own forms rather than use this module for it (unless the needs are very simple).
  16. It's hard to say here. The one at thresholdstate.com is Textile 2.0 and we're using Textile 2.2 (a newer version). I don't know enough about Textile or it's code to be able to debug it very easily, so I think we should try to look at all other factors. Do you have any other text formatters applied to the field where textile is applied? Where did you read about others solving this problem with a <br>? It makes me wonder if this is some known issue with Textile. Also, can you post the full textile code that is failing? I'd like to try and duplicate it here.
  17. Since we're trying to take advantage of a side effect of the modal box that you are using, I'm not sure I can properly troubleshoot this without being placed into it. Do you have a URL I can visit?
  18. Welcome to the forums! Thanks for posting and sharing your template. It looks like you've put together a nice template and I like the output it produces! There are always ways to improve something, and how far you take it really depends other factors. The factors here would be no different than in any other PHP script. For instance, the example you posted could be improved by moving the styles to their own css file, moving the code into functions (or even a class), providing more (or full) separation between output and logic code and moving the output variables (like image size, template names, text labels) to some easily changeable constants or variables at the top. Lastly, unrelated to PHP, but you could use $input->urlSegment(n) instead of a GET var so that your pages could be cached. Or, if you want to use GET vars, then use PW's $input->get rather than PHP's $_GET. But so long as something is secure and meets your needs and those that will be maintaining it, then you are in a good place. If you are building something that you'll be reusing or others will, then it's good to go further with some of these practices. But ultimately PW is here to support your work rather than define it for you. If there were two immediate changes I would suggest, it would be to figure out how to get your styles out of your template file and into their own CSS file, and replace this: $image = $images->get($_GET[img]); with this: $image = $images->get($sanitizer->name($input->get->img)); The above is just a security best practice to make sure that any user input is appropriately sanitized before being sent anywhere else.
  19. I'm not sure that I understand the question well enough. If you are using PW's built-in access control, then the pagination should be consistent with the pages the user has access to. But if you instead want it to include the pages the user doesn't have access to, you'd want to add "check_access=0" to your selector that does the $pages->find() or $page->children().
  20. Great solution, thanks for posting this Pete. I figure I should follow-up and post the route that I use too, though this one depends on the server running unix. It creates rotating backups off your non-web-accessible home directory with a cron job, and then a cron job on your machine (or another server) copies the backups over every day. 1. Login to your unix-based web account (SSH or FTPS/SFTP) and create a directory off your non-web-accessible home directory where the backups will be stored. I call mine /db-backups/: mkdir /home/your-account/db-backups 2. Create a file in your home directory called .my.cnf (starting with a period). This holds your DB connection information. Place the following into that file, replacing "mysql_username" with your database username, and "mysql_password" with your database password: /home/your-account/.my.cnf [client] user=mysql_username pass=mysql_password If working on a shared server or some environment where other accounts can get into your files, make sure that .my.cnf file isn't readable by anyone else. i.e. type "chmod og-rwx .my.cnf" to remove (o)ther and (g)roup read/write/execute access to it. 3. Create another file in your non-web-accessible home directory called db-backup and paste the following in there. Update the first two lines in the script to point to the directory you created in step 1 (DB_BACKUP) and the name of the database you want to backup (DB_NAME). /home/your-account/db-backup #!/bin/bash # modify the following to suit your environment DB_BACKUP="/home/your-account/db-backups" DB_NAME="your-db-name" # title and version echo "" echo $DB_NAME echo "----------------------" echo "* Rotating backups..." rm $DB_BACKUP/$DB_NAME.5.sql mv $DB_BACKUP/$DB_NAME.4.sql $DB_BACKUP/$DB_NAME.5.sql mv $DB_BACKUP/$DB_NAME.3.sql $DB_BACKUP/$DB_NAME.4.sql mv $DB_BACKUP/$DB_NAME.2.sql $DB_BACKUP/$DB_NAME.3.sql mv $DB_BACKUP/$DB_NAME.1.sql $DB_BACKUP/$DB_NAME.2.sql echo "* Creating new backup..." mysqldump $DB_NAME > $DB_BACKUP/$DB_NAME.1.sql echo "----------------------" echo "Done" Note: I found this code somewhere else online a couple years ago and don't remember where to properly credit it. 4. Save the above and make it executable: chmod u+x db-backup If you are connected via SSH, test it out to make sure it's working by typing: ./db-backup It should create the first backup in your ./db-backups/ directory. 5. Setup a daily cron job to execute that file: /home/your-account/db-backup … most web hosting accounts have some ability to setup cron jobs in the control panel. 6. Now your server is keeping rotating backups in your account. Next I'd recommend going further and copying them to another machine, automatically every day. How you do this depends on whether you are going to use SFTP/FTPS or SSH (with rsync). Its preferable not to use regular FTP since it's not secure. In my case, I've setup a cron job on my OS X desktop to copy over the files to my computer every day. It executes a file that looks like this: #!/bin/bash /usr/bin/rsync --archive --rsh=/usr/bin/ssh --verbose user@domain.com:db-backups/* /Users/ryan/Backups/db/ That copies those rotating backups to a /Users/ryan/Backups/db/ directory on my computer. In order for the above to work, you'd have to already be using SSH with your account and have your SSH keys assigned so that you can connect without typing your login/password. If anyone is running a similar setup, I'll be glad to tell you how to do that. But I know there are other ways to automate this task and the approach you use here kind of depends on the platform and whether you have SSH access on the server. This setup is pretty bulletproof, but I'd like to have some module in PW in the future that will let it do all of this for you – Automatic backups from one server to another.
  21. Permalinks are still a good idea in your case because you have reverse chronological blog pages displaying 3 entries per page. If someone wants to link to one of those, you want them to link to the entry's full URL (permalink) rather than the paginated entries. I was just trying to say that it'd be preferable for your permalink to be just ProcessWire's URL to the page, rather than some other system of URLs on top of that. If you need to go outside that, then you could have the same entry by itself living at two URLs in your site. To minimize SEO issues, you'd want to use an canonical meta tag to make it clear to Google what the actual permanent home of that entry is. Still, if possible, save yourself the trouble and use a structure that doesn't need to change regularly and I think you'll get better performance out of it.
  22. ryan

    Log messages

    bpz, welcome to the forums. Good question. You'll want to use the FileLog class: <?php $log = new FileLog($config->paths->logs, 'your-log-name'); $log->save("Your log message goes here"); In 'your-log-name', leave off an extension as it automatically adds a .txt extension. You'll find your log file in /site/assets/logs/. Throwing an exception is what you'd want to do if the error is fatal and you want execution to stop. It's preferable to throw a WireException rather than a normal Exception. Pass the error message to the exception. i.e. throw new WireException("your error message here"); Here are the most common exception classes in PW: WirePermissionException – what to throw when access denied and execution should stop Wire404Exception – what to throw when resource doesn't exist and 404 page should appear WireException – any other fatal error
  23. Are permalinks really necessary outside of a blog? I always thought the point of them was to provide a permanent link for stories that appear on the homepage and in date ordered paginated pages. Since the page they would appear on keeps changing with the number of entries, a permalink is necessary to establish a long term URL for the story. But it seems unnecessary outside of that environment. A page URL in PW is really no different than a permalink elsewhere (?). With a blog in PW, I would just use the entry's page URL as the permalink when needed in date ordered presentation. My opinion is that it's good to build around a URL structure that you consider permanent. And when/if you need to change it, use 301 redirects.
  24. Maruchan, these are all good suggestions. Also look at the ProcessExportProfile module which includes a PHP native database export function. Perhaps I should repurpose it to module just for doing DB backups.
×
×
  • Create New...