Jak na výpis z databáze a vložení dat? (počítadlo návštěvnosti)

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
Zuben45
Člen | 268
+
0
-

Dobrý den, potřeboval bych pomoct, tvořím si vlastní návštěvnost a nemůžu přijít na to jak to udělat v nette, normálně to není problém, ale tady fakt netuším :(

mám tabulku pocitadlo s kolonkamy ip,datum,cas

A teď nastává problém, z návodů jsem vůbec nepochopil jak bych to mohl použít.

V app/model jsem si vytvořil soubor Navstevnost.php

<?php
namespace Pocitadlo;
use Nette;
use Nette\Database\Connection;

class Pocitadlo extends Table
{
  $database = new Connection($dsn,$user,$password);
  $ip = $_SERVER['REMOTE_ADDR'];

  public function getOnline()
  {
    $database->query("SELECT * FROM pocitadlo WHERE datum=NOW() and ip='$ip'");
  }

}

a zařadil ho také jako službu

	services:
		database: @Nette\Database\Connection
		authenticator: Authenticator
		navstevnost: Navstevnost( 'pocitadlo' )

prosím pomohl by mi někdo ? Díky moc

Jinak normálně to mám nějak takhle:

function pocitadlo()
{
	$ip = $_SERVER["REMOTE_ADDR"];
	$dotaz = mysql_query("SELECT * FROM pocitadlo WHERE datum=NOW() AND ip='$ip'");

 	if (mysql_num_rows($dotaz))
	{
		$dotaz2 = mysql_query("UPDATE pocitadlo SET cas='".time()."' WHERE datum=NOW() AND ip='$ip'");
	}
	else
	{
		$dotaz2 = mysql_query("INSERT INTO pocitadlo (ip, datum, cas) VALUES('$ip',NOW(),'".time()."');");
	}
}
function navstevy()
{
	$navstevnici = array();
	$dotaz = mysql_query("SELECT count(*) FROM pocitadlo");
	list($navstevnici['celkem'])=mysql_fetch_array($dotaz);
	$dotaz = mysql_query("SELECT count(*) FROM pocitadlo WHERE datum=NOW()");
	list($navstevnici['dnes'])=mysql_fetch_array($dotaz);

	$dotaz = mysql_query("SELECT count(*) FROM pocitadlo WHERE datum=NOW() AND cas>='".(time()-180)."'");
	list($navstevnici['online'])=mysql_fetch_array($dotaz);

# vratime pole
# $navstevnici['celkem'] = pocet navstev celkem
# $navstevnici['dnes'] = pocet navstev za dnesni den
# $navstevnici['online'] = pocet navstev, ktere nejsou starsi jak 3 minuty
return $navstevnici;
}




pocitadlo();
$navstevnici = navstevy();

echo "ONLINE: $navstevnici[online]<br>
DNES: $navstevnici[dnes]<br>
CELKEM: $navstevnici[celkem]<br>";

EDIT: Kdyby mi někdo vysvětlil základní tvorbu výpisu a vkládání dat z/do db (pro NF, normálně to umím ;) ), tak bych byl moc rád

Editoval Zuben45 (17. 8. 2013 13:18)

Oli
Člen | 1215
+
0
-

Řekl bych, že to nepoužíváš dobře. Já bych na to šel zhruba takhle:

neon:

services:
    database: @Nette\Database\Connection
    authenticator: Authenticator
    pocitadlo: Pocitadlo\Pocitadlo(@httpRequest) // Předá třídě počitadlo objekt httpRequest
    navstevnost: Navstevnost( @pocitadlo ) // Předá třídě Návštěvnost objekt pocitadlo

Presenter:

protected $pocitadlo;
protected $navstevnost;

function __construct(\Pocitadlo\Pocitadlo $pocitadlo, Navstevnost $navstevnost)
{
	$this->pocitadlo = $pocitadlo;
	$this->navstevnost = $navstevnost;

	public function actionDefault()
	{
		$online = $this->pocitadlo->getOnline();
		$pocet = $online->count(); // Pocet záznamů v tabulce pro zadaný výraz
	}
}

pocitadlo:

namespace Pocitadlo;

class Pocitadlo extends \Nette\Object
{
	private $_db;
	private $httpRequest;

	function __construct($httpRequest, \Nette\Database\Connection $db)
	{
		$this->_db = $db;
		$this->httpRequest = $httpRequest;
	}

	public function getOnline()
	{
		return $this->_db->table('pocitadlo')->where(
			'datum = ? && ip = ?',
			new \Nette\DateTime(), $this->httpRequest->getRemoteAddress()
		);
	}

	public function delete($id)
	{
		$this->_db->table('pocitadlo')->wherePrimary($id)->delete();
	}

	public function editOrAdd($id, Array $arr)
	{
        	if($id == null)
        	{
            		$lastInsert = $this->_db->table($this->table)->insert($arr);
            		return $lastInsert;
        	} else
        	{
            		$lastUpdate = $this->_db->table($this->table)->where("id = ?", $id)->update($arr);
            		return $lastUpdate;
        	}
    }
}

Psal jsem to z fleku, nemusí to být přesně. Nevím jestli to je úplně nejlepší postup, ale řekl bych, že je správnější než tvůj :-)

víc by ti mohlo mopomoct: Databáze & ORM, Getting started (Getting started je i časky, ale neaktualizuje se)

//Edit: Vkládání, editace, mazání v db

Editoval Oli (17. 8. 2013 13:38)

Zuben45
Člen | 268
+
0
-

Supr, už to trochu začínám chápat, a když pak chci vypsat $pocet, tak to udělám pls jak ?

jinak, vypisuje mi to chybu

Class Navstevnost used in service 'navstevnost' has not been found or is not instantiable

Třída Návštevnost použita ve službě ‚navstevnost‘ nebyla nalezena nebo není …, nevím jak to vyřešit :(

Editoval Zuben45 (17. 8. 2013 15:02)

ViPEr*CZ*
Člen | 818
+
0
-

Jen doplním pár lepších (jednodušších) zápisů. Prvně bych _db klidně pojmenoval jen db.

->where('datum = ? && ip = ?',
            new \Nette\DateTime(), $this->httpRequest->getRemoteAddress()

toto je přehlednější podle mě do dvou where

->where('datum', new \Nette\DateTime())
->where('ip', $this->httpRequest->getRemoteAddress());

Toto

$this->_db->table('pocitadlo')->wherePrimary($id)->delete();

lze takto

$this->_db->table('pocitadlo')->get($id)->delete();

->where(„id = ?“, $id) je totéž jako ->where(„id“, $id)

na porovnání $id == null bych raději použil $id === null

Zuben45
Člen | 268
+
0
-

Teď jsem zkoušel to použít s pomocí Repository jak jsou v návodu, počet online a celkem jde, jen mi nejde vkládat data, kod mam tento:

NavstevnostRepository.php

<?php

namespace Todo;
use Nette;

/**
 * Tabulka navstevnost
 */

class NavstevnostRepository extends Repository
{
  private $httpRequest;

  function __construct($httpRequest)
  {
    $this->httpRequest = $httpRequest;
  }

  public function CelkemNavstevnost()
  {
    $CelkemNav = $this->findAll();
    return $CelkemNav->count();
  }
  public function getOnlineNavstevnost()
  {
    return $this->findBy(array('datum' =>"Now()"))->count();
  }

  public function createNavstevnost()
  {
    $ip = $this->httpRequest->getRemoteAddress();

    if($ip === null)
    {
      return $this->getTable()->insert(array(
        'ip' => $ip,
        'datum' => new \DateTime()
      ));
    }
  }
}
<?php

/**
 * Homepage presenter.
 */
class HomepagePresenter extends BasePresenter
{
  private $taskRepository;
  private $navstevnostRepository;

  protected function startup()
  {
    parent::startup();
    $this->taskRepository = $this->context->taskRepository;
    $this->navstevnostRepository = $this->context->navstevnostRepository;
  }

	public function renderDefault()
	{
		$this->template->tasks = $this->taskRepository->findIncomplete();
		$pocet = $this->taskRepository->findIncomplete();
    $this->template->pocet = $pocet->count();

    $ncelkem = $this->navstevnostRepository->CelkemNavstevnost();
    $this->template->navstevnostcelkem = $ncelkem;
    $nonline = $this->navstevnostRepository->getOnlineNavstevnost();
    $this->template->navstevnostonline = $nonline;
	}
}

ale teď mi to hází chybu

Call to a member function table() on a non-object

Editoval Zuben45 (17. 8. 2013 19:17)

Oli
Člen | 1215
+
0
-

actionDefault totiž nemá v repository co dělat, pokud teda to není nějaká tvoje metoda. ActionDefault a renderDefault jsou metody Presenteru: MVC aplikace & presentery.

presenter:

protected $navstevnost;

function __contruct(Todo\NavstevnostRepository $navstevnost)
{
	$this->navstevnost = $navstevnost;
}

// ip zjistíš pres httpRequest, nenní potřeba ho předávat parametrem.
public function actionDefault()
	{
		$>ip = $this->httpRequest->getRemoteAddress();

		if($this->ip == null)
		{
			$Insert = $this->navstevnost->insert(array('ip' => $ip,'datum' => 'NOW()');
		}
	}
}

model:

public function insert(Array $arr)
{
	$lastInsertId = $this->db->table('nazev_tabulky')->insert($arr);
	return $lastInsertId;
}

Lepší než přes context je předávat si databazi přes konstruktor. V mém prvním příspěvku jsem ti to psal i s nastavením v configu, jak by to mělo fungovat

Zuben45
Člen | 268
+
0
-

no teď mi ale zase hází chybu s db

Argument 1 passed to Todo\Repository::__construct() must be an instance of Nette\Database\Connection, instance of Nette\Http\Request given, called in C:\xampp\htdocs\nette framework 2\sandbox\temp\cache\_Nette.Configurator\_-967fb136ca1226356bf18e9532238eb7.php on line 178 and defined
13:        public function __construct(Nette\Database\Connection $db)
<?php

/**
 * Homepage presenter.
 */
class HomepagePresenter extends BasePresenter
{
  private $taskRepository;
  private $httpRequest;
  protected $navstevnost;

  function __construct(Todo\NavstevnostRepository $navstevnost)
  {
    $this->navstevnost = $navstevnost;
    $this->httpRequest = $httpRequest;
  }
  protected function startup()
  {
    parent::startup();
    $this->taskRepository = $this->context->taskRepository;
  }

	public function renderDefault()
	{
		$this->template->tasks = $this->taskRepository->findIncomplete();
		$pocet = $this->taskRepository->findIncomplete();
    $this->template->pocet = $pocet->count();

    $ncelkem = $this->navstevnost->CelkemNavstevnost();
    $this->template->navstevnostcelkem = $ncelkem;
    $nonline = $this->navstevnost->getOnlineNavstevnost();
    $this->template->navstevnostonline = $nonline;
	}
  public function actionDefault()
  {
    $ip = $this->httpRequest->getRemoteAddress();

    if($ip == null)
    {
      $Insert = $this->navstevnost->insert(array('ip' => $ip,'datum' => 'NOW()'));
    }
  }
}
<?php

namespace Todo;
use Nette;

/**
 * Tabulka navstevnost
 */

class NavstevnostRepository extends Repository
{

  public function CelkemNavstevnost()
  {
    $CelkemNav = $this->findAll();
    return $CelkemNav->count();
  }
  public function getOnlineNavstevnost()
  {
    return $this->findBy(array('datum' =>"Now()"))->count();
  }

  public function insert(Array $arr)
  {
    $lastInsertId = $this->getTable->insert($arr);
    return $lastInsertId;
  }
}

Editoval Zuben45 (17. 8. 2013 19:34)

Oli
Člen | 1215
+
0
-

Myslím, že jsi použil ten config co jsem ti psal na začátku. Tahle hláška by tomu odpovídala. Jde o to, že v tom configu říkáš, třídě Todo\Repository předej objekt httpRequest. Jestli to chápu dobře, tak databáze se tam vloží automaticky. A konstruktor by teda měl vypadat takhle:

__construct(Nette\Http\Request $httpRequest, Nette\Database\Connection $db)
Zuben45
Člen | 268
+
0
-

Oli napsal(a):

Myslím, že jsi použil ten config co jsem ti psal na začátku. Tahle hláška by tomu odpovídala. Jde o to, že v tom configu říkáš, třídě Todo\Repository předej objekt httpRequest. Jestli to chápu dobře, tak databáze se tam vloží automaticky. A konstruktor by teda měl vypadat takhle:

__construct(Nette\Http\Request $httpRequest, Nette\Database\Connection $db)

ty jo, tak já už tomu frameworku snad už neporozumím :/ , ten konstruktor patří do presentu že ? U mě v HomepagePresenter.php

neměl by spíš vypadat takhle ?

function __construct(Todo\NavstevnostRepository $navstevnost, Nette\Http\Request $httpRequest, Nette\Database\Connection $db)

a v tom configu mám to na tu návštěvnost

navstevnostRepository: Todo\NavstevnostRepository(@httpRequest)

ale i tak mi to hází stejnou chybu

Editoval Zuben45 (17. 8. 2013 22:25)

Oli
Člen | 1215
+
0
-

Ne. V configu rikas: navstevnostRepository dostane zavislost httpRequest. Connection dostane jako bonus automaticky.
V presenteru reknes, pro tenhle presenter chci tridu NavstevnostRepository, kterou si ulozis do napr $this->navstevnost. Tahle promenna ted obsahuje objekt NavstevnostRepository. V cofigu jsi mu predal do konsttruktoru ten httpRequest a connection. Ted si to musis v te tride NavstevnostRepository jen vyzvednout.

Je to takhle trochu pochopitelny? :)

Zuben45
Člen | 268
+
0
-

Oli napsal(a):

Ne. V configu rikas: navstevnostRepository dostane zavislost httpRequest. Connection dostane jako bonus automaticky.
V presenteru reknes, pro tenhle presenter chci tridu NavstevnostRepository, kterou si ulozis do napr $this->navstevnost. Tahle promenna ted obsahuje objekt NavstevnostRepository. V cofigu jsi mu predal do konsttruktoru ten httpRequest a connection. Ted si to musis v te tride NavstevnostRepository jen vyzvednout.

Je to takhle trochu pochopitelny? :)

takže, v NavstevnostRepository musím mít

private $httpRequest;
$this->httpRequest = $httpRequest;

a

$ip = $this->httpRequest->getRemoteAddress();

?

EDIT: nejlepší to je ukázat na příkladu, mohl bys prosímtě ? děkuji

Editoval Zuben45 (17. 8. 2013 22:59)

Oli
Člen | 1215
+
0
-

To zalezi na tobe, kde tu IP ziskas. Pokud mas ale v configu

navstevnostRepository: NavstevnostRepository(@httpRequest)

Tak musi byt v konstruktoru prvne $httpRequest a az potom $db.

Priklad, snad dobre, je muj prvni prispevek. Presne takhle by meli vypadat konstruktory presenteru a NavstecnostRepository…

Editoval Oli (17. 8. 2013 23:11)

Zuben45
Člen | 268
+
0
-

Oli napsal(a):

To zalezi na tobe, kde tu IP ziskas. Pokud mas ale v configu

navstevnostRepository: NavstevnostRepository(@httpRequest)

Tak musi byt v presenteru prvne $httpRequest a az potom $db.

Priklad, snad dobre, je muj prvni prispevek. Presne takhle by meli vypadat konstruktory presenteru a NavstecnostRepository…

$db musím taky, když to dělám přes Repository.php ?

Oli
Člen | 1215
+
0
-

Jsem se upsal, editoval, ale ty jsi byl rychlejsi :)

V presenteru ma konstruktor jen NavstevnostRepository nebo PocetRepository, zalezi na tom, co chces. A az pocet\NavstevnostRepository ma db pripadne httpRequest,jestli jsi mu ho v configu nastavil.

V tom prvnim mem prispevku to je nazorne ;)

ViPEr*CZ*
Člen | 818
+
0
-

Btw co Vám vrací $this->findAll(); ??? Object NDB Selection? Pak asi raději použijete:

$CelkemNav = $this->findAll();
return $CelkemNav->count('*');

To vygeneruje jen COUNT(*) SQL dotaz a nebudou se stahovat všechna data.

Zuben45
Člen | 268
+
0
-

Už mi všechno jde

<?php
namespace Pocitadlo;

class Pocitadlo extends \Nette\Object
{
    private $_db;
    private $httpRequest;

    function __construct($httpRequest, \Nette\Database\Connection $db)
    {
        $this->_db = $db;
        $this->httpRequest = $httpRequest;
    }

    public function getOnline()
    {
        return $this->_db->table('navstevnost')->where(
            'datum = ? && ip = ?',
            new \Nette\DateTime(), $this->httpRequest->getRemoteAddress()
        );
    }

    public function getCelkem()
    {
        return $this->_db->table('navstevnost')->count();
    }

    public function addNavstevnik()
    {
      $ip = $this->httpRequest->getRemoteAddress();
      $existIp = $this->_db->table('navstevnost')->where('ip = ?',$ip)->count();
      if($existIp == 0)
      {
        $lastInsert = $this->_db->table('navstevnost')->insert(array('ip' => $ip,'datum' => new \DateTime()));
        return  $lastInsert;
      }

    }
}
<?php

/**
 * Homepage presenter.
 */
class HomepagePresenter extends BasePresenter
{
  private $taskRepository;
  protected $pocitadlo;

function __construct(\Pocitadlo\Pocitadlo $pocitadlo)
{
    $this->pocitadlo = $pocitadlo;
}
    public function actionDefault()
    {
        $online = $this->pocitadlo->getOnline();
        $onlinepocet = $online->count(); // Pocet záznamů v tabulce pro zadaný výraz
        $this->pocitadlo->addNavstevnik();
    }
	public function renderDefault()
	{
    		$online = $this->pocitadlo->getOnline();
    		$onlinepocet = $online->count(); // Pocet záznamů v tabulce pro zadaný výraz
   		$this->template->navstevnostonline = $onlinepocet;
    		$this->template->navstevnostcelkem = $this->pocitadlo->getCelkem();
	}
}

jen teď nevím jak se dá přičítat nebo odečítat od DateTime (chtěl bych příčíst 60min, kvůli hodnotě online, protože teď jak to mám, to započítává jen když je někdo přesně v tu sekundu minutu… na stránce)

Mám tento příkaz:

$cas = $this->_db->table('navstevnost')->where('ip = ? && cas >= ?',$ip,time()-180)->count();

elseif($cas == 1)
{
  $lastUpdate = $this->_db->table('navstevnost')->where("ip = ?", $ip)->update(array('datum' => Date("Y-m-d"),'cas' => Date("H:i:s")));
  return $lastUpdate;
}

ale po uplynutí 3 minut se nic neděje :(

Editoval Zuben45 (18. 8. 2013 16:06)

Zuben45
Člen | 268
+
0
-

Vyřešeno, můžete LOCK ;)