given the following link:
http://finanzalocale.interno.it/apps/floc.php/certificati/index/codice_ente/1030491450/cod/4/anno/2012/md/0/cod_modello/CCOU/tipo_modello/U/cod_quadro/01
how am I supposed to scrpae the value of Popolazione residente (ab.)?
I have tried with some prehistorical code of mine, but it's terribly slow and many datas get unprocessed.
For example if I process 300 links, about 180/200 are not processed.
Any clue?
Thanks.
First of all it is verry difficult due to the fact that the first table doesn`t have a unique identifier(nor id nor class).
THIS WILL NOT WORK FOR EVERY PAGE!!!, it's more of an option at this point.
You would have to change the implementation depending on other page content with a case depending on the link I suppose....
I would use https://github.com/fabpot/goutte and implement something like this:
class MyController ...
public function __construct()
{
$this->count = 0; //no iteration
$this->scraped = array();
}
.....
public function scrape($url)
{
$crawler = $client->request('GET', $url);
$crawler->filter('table > tbody >tr >td')->each(function ($node) { //find all td`s
$this->count++;//increment
if($this->count == 1)
{//if first td with the text you want...
$this->scraped[] = $node->text();
}
});
}
Related
So I've built a small conditional to evaluate which button is pressed in my form (as there are 2). This works fine and fires off the correct method and writes the appropriate data to the DB, however my redirect is not working. It saves() to the DB and then simply stays on the page designated as the POST route.
I suspect the problem has something to do with my conditional and the use of $this.
Here is my check_submit method:
public function check_submit()
{
if(!is_null(Input::get('add_to_invoice'))){
$this->invoice_add_item();
} elseif(!is_null(Input::get('complete_invoice'))) {
$this->invoice_complete();
}
}
Here is one of the 2 methods which I am currently testing:
public function invoice_add_item()
{
$input = Request::all();
$invoice_items = new Expense;
$invoice_items->item_id = $input['item_id'];
$invoice_items->category_id = $input['category'];
$invoice_items->price = $input['price'];
$invoice_items->store_id = $input['store'];
if(Input::has('business_expense'))
{
$invoice_items->business_expense = 1;
}
else{
$invoice_items->business_expense = 0;
}
$invoice_items->save();
return redirect('/');
}
Perhaps there is a better way of handling this in my routes(web) file, but I'm not sure how to go about this.
You should add the return to the check_submit() method. Something like
public function check_submit()
{
if(!is_null(Input::get('add_to_invoice'))){
return $this->invoice_add_item();
} elseif(!is_null(Input::get('complete_invoice'))) {
return $this->invoice_complete();
}
}
Better yet, you should probably return a boolean on invoice_add_item() and based on that, redirect the user to the correct place (or with some session flash variable with an error message)
I want to implement a system in my project that "alerts" users when there is a new comment on one of their posts.
I currently query all comments on the posts from the logged in user and put everything in an array and send it to my view.
Now my goal is to make an alert icon or something when there is a new item in this array. It doesn't have to be live with ajax just on page load is already good :)
So I've made a function in my UsersController where I get the comments here's my code
public function getProfileNotifications()
{
$uid = Auth::user()->id;
$projects = User::find($uid)->projects;
//comments
if (!empty($projects)) {
foreach ($projects as $project) {
$comments_collection[] = $project->comments;
}
}
if (!empty($comments_collection)) {
$comments = array_collapse($comments_collection);
foreach($comments as $com)
{
if ($com->from_user != Auth::user()->id) {
$ofdate = $com->created_at;
$commentdate = date("d M", strtotime($ofdate));
$comarr[] = array(
'date' => $ofdate,
$commentdate,User::find($com->from_user)->name,
User::find($com->from_user)->email,
Project::find($com->on_projects)->title,
$com->on_projects,
$com->body,
Project::find($com->on_projects)->file_name,
User::find($com->from_user)->file_name
);
}
}
} else {
$comarr = "";
}
}
Is there a way I can check on page load if there are new items in the array? Like keep a count and then do a new count and subtract the previous count from the new one?
Is this even a good way to apprach this?
Many thanks in advance! Any help is appreciated.
EDIT
so I added a field unread to my table and I try to count the number of unreads in my comments array like this:
$uid = Auth::user()->id;
$projects = User::find($uid)->projects;
//comments
if (!empty($projects)) {
foreach ($projects as $project) {
$comments_collection[] = $project->comments;
}
}
$unreads = $comments_collection->where('unread', 1);
dd($unreads->count());
But i get this error:
Call to a member function where() on array
Anyone any idea how I can fix this?
The "standard" way of doing this is to track whether the comment owner has "read" the comment. You can do that fairly easily by adding a "unread" (or something equivalent) flag.
When you build your models, you should define all their relationships so that stuff like this becomes relatively easy.
If you do not have relationships, you need to define something like the following:
In User
public function projects()
{
return $this->hasMany('App\Models\Project');
}
In Project
public function comments()
{
return $this->hasMany('App\Models\Comment');
}
Once you hav ethose relationshipt, you can do the following. Add filtering as you see fit.
$count = $user->projects()
->comments()
->where('unread', true)
->count();
This is then the number you display to the user. When they perform an action you think means they've acknowledged the comment, you dispatch an asynchronous request to mark the comment as read. A REST-ish way to do this might look something like the following:
Javascript, using JQuery:
jQuery.ajax( '/users/{userId}/projects/{projectId}/comments/{commentId}', {
method: 'patch'
dataType: 'json',
data: {
'unread': false
}
})
PHP, in patch method:
$comment = Comment::find($commentId);
$comment->update($patchData);
Keep in mind you can use Laravel's RESTful Resource Controllers to provide this behavior.
try this
$unreads = $project->comments()->where('unread', 1);
dd($unreads->count());
EDIT
My be Has Many Through relation will fit your needs
User.php
public function comments()
{
return $this->hasManyTrough('App\Project', 'App\Comment');
}
Project.php
public function comments()
{
return $this->hasMany('App\Comment');
}
then you can access comments from user directly
$user->comments()->where('unread', 1)->count();
or I recommend you define hasUnreadComments method in User
public function hasUnreadComments()
{
$return (bool) $this->comments()->where('unread', 1)->count();
}
P.S.
$uid = Auth::user()->id;
$projects = User::find($uid)->projects;
this code is horrible, this way much better
$projects = Auth::user()->projects;
I have a function that takes an input variable and outputs a template with the following call:
outputhtml($blue_widget);
outputhtml($red_widget);
outputhtml($green_widget);
And a simplified version of the function:
function outputhtml($type)
{
static $current;
if (isset($current))
{
$current++;
}
else
{
$current = 0;
}
//some logic here to determine template to output
return $widget_template;
}
Now here is my problem. If I call the function in a script three times or more, I want the output to be one way, but if I only call the function twice, then I have some html changes that need to be reflected in the templates that are returned.
So how can I modify this function to determine if there are only two calls for it. I can't go back after the fact and ask "hey function did you only run twice???"
Having trouble getting my head around how I tell a function that it is not going to be used after the second time and the necessary html modifications can be used. How would I go about accomplishing this?
function outputhtml($type)
{
static $current = 0;
$current++;
//some logic here to determine template to output
if ($current === 2) {
// called twice
}
if ($current > 2) {
// called more than twice
}
return $widget_template;
}
That would not be practical using a static $current inside the function; I would suggest using an object to maintain the state instead, like so:
class Something
{
private $current = 0;
function outputhtml($type)
{
// ... whatever
++$this->current;
return $template;
}
function didRunTwice()
{
return $this->current == 2;
}
}
The didRunTwice() method is asking "did you run twice?".
$s = new Something;
$tpl = $s->outputhtml(1);
// some other code here
$tpl2 = $s->outputhtml(2);
// some other code here
if ($s->didRunTwice()) {
// do stuff with $tpl and $tpl2
}
The only way you can find out if a function was only called twice is by putting the test at the end of your code; but perhaps by then the templates are no longer accessible? Can't tell much without seeing more code.
I'm building a tutorialsystem with codeigniter and would like to achieve the following URL structure:
/tutorials --> an introduction page with the list of all the categories
/tutorials/{a category as string} --> this will give a list of tutorials for the given category, e.g. /tutorials/php
/tutorials/{a category as string}/{an ID}/{tutorial slug} --> this will show the tutorial, e.g. /tutorials/php/123/how-to-use-functions
/tutorials/add --> page to add a new tutorial
The problem is that when I want to use the first two types of URLs, I'd need to pass parameters to the index function of the controller. The first parameter is the optional category, the second is the optional tutorial ID. I've did some research before I posted, so I found out that I could add a route like tutorials/(:any), but the problem is that this route would pass add as a parameter too when using the last URL (/tutorials/add).
Any ideas how I can make this happen?
Your routing rules could be in this order:
$route['tutorials/add'] = "tutorials/add"; //assuming you have an add() method
$route['tutorials/(:any)'] = "tutorials/index"; //this will comply with anything which is not tutorials/add
Then in your controller's index() method you should be able to work out whether it's the category or tutorial ID is being passed!
I do think that a remap must be of more use to your problem in case you want to add more methods to your controller, not just 'add'. This should do the task:
function _remap($method)
{
if (method_exists($this, $method))
{
$this->$method();
}
else {
$this->index($method);
}
}
A few minutes after posting, I think I've found a possible solution for this. (Shame on me).
In pseudo code:
public function index($cat = FALSE, $id = FALSE)
{
if($cat !== FALSE) {
if($cat === 'add') {
$this->add();
} else {
if($id !== FALSE) {
// Fetch the tutorial
} else {
// Fetch the tutorials for category $cat
}
}
} else {
// Show the overview
}
}
Feedback for this solution is welcome!
The pagination in Symfony is pretty straightforward and pretty good. However I'm looking for the best direction to go for adding in Sorting to the table.
My thoughts are that the sorting column, direction and current page number are defined in the uri, like this:
http://www.mysite.com/backend_dev.php/articles/author/asc/3/
And then on each page, Symfony uses the uri to determine the current sorting column, direction and page and then manipulates all the pagination links to take those things into account so that when you click on a link to change pages or sort by a different column it takes you to the proper place.
Does anyone have any other directions I could go with this? I know about the simplicity of jQuery's tablesorter plugin but it sucks when there are 1000+ records because you have to load them all at once to make that plugin work.
The generator admin has an interesting approach. It gets the sorting from URI as well like below.
/backend_dev.php/pedidos?sort=status&sort_direction=asc
In order not to carry those get parameters throughout the links (it's a pain to do that), it stores in the user session. Let's see an example. In the action you'll have
public function executeIndex(sfWebRequest $request)
{
// sorting
if ($request->getParameter('sort') && $this->isValidSortColumn($request->getParameter('sort')))
{
$this->setSort(array($request->getParameter('sort'), $request->getParameter('sort_type')));
}
// pager
if ($request->getParameter('page'))
{
$this->setPage($request->getParameter('page'));
}
$this->pager = $this->getPager();
$this->sort = $this->getSort();
}
//// more code
protected function setPage($page)
{
$this->getUser()->setAttribute('ef3Pedido.page', $page, 'admin_module');
}
protected function getPage()
{
return $this->getUser()->getAttribute('ef3Pedido.page', 1, 'admin_module');
}
protected function getSort()
{
if (null !== $sort = $this->getUser()->getAttribute('ef3Pedido.sort', null, 'admin_module'))
{
return $sort;
}
$this->setSort($this->configuration->getDefaultSort());
return $this->getUser()->getAttribute('ef3Pedido.sort', null, 'admin_module');
}
protected function setSort(array $sort)
{
if (null !== $sort[0] && null === $sort[1])
{
$sort[1] = 'asc';
}
$this->getUser()->setAttribute('ef3Pedido.sort', $sort, 'admin_module');
}
protected function isValidSortColumn($column)
{
return Doctrine::getTable('Pedido')->hasColumn($column);
}
It's a nice approach for both, the end user and the developer.